aboutsummaryrefslogtreecommitdiffstats
path: root/lib/edoc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/edoc')
-rw-r--r--lib/edoc/priv/edoc.dtd4
-rw-r--r--lib/edoc/src/edoc.erl9
-rw-r--r--lib/edoc/src/edoc.hrl6
-rw-r--r--lib/edoc/src/edoc_data.erl3
-rw-r--r--lib/edoc/src/edoc_doclet.erl28
-rw-r--r--lib/edoc/src/edoc_extract.erl16
-rw-r--r--lib/edoc/src/edoc_layout.erl15
-rw-r--r--lib/edoc/src/edoc_lib.erl67
-rw-r--r--lib/edoc/src/edoc_macros.erl4
-rw-r--r--lib/edoc/src/edoc_parser.yrl12
-rw-r--r--lib/edoc/src/edoc_refs.erl19
-rw-r--r--lib/edoc/src/edoc_wiki.erl3
12 files changed, 116 insertions, 70 deletions
diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd
index 6a332cf22f..ba4ac0db28 100644
--- a/lib/edoc/priv/edoc.dtd
+++ b/lib/edoc/priv/edoc.dtd
@@ -4,7 +4,8 @@
<!ELEMENT overview (title, description?, author*, copyright?, version?,
since?, see*, reference*, todo?, packages, modules)>
<!ATTLIST overview
- root CDATA #IMPLIED>
+ root CDATA #IMPLIED
+ encoding CDATA #IMPLIED>
<!ELEMENT title (#PCDATA)>
@@ -25,6 +26,7 @@
name CDATA #REQUIRED
private (yes | no) #IMPLIED
hidden (yes | no) #IMPLIED
+ encoding CDATA #IMPLIED
root CDATA #IMPLIED>
<!ELEMENT description (briefDescription, fullDescription?)>
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index 544465b14a..599036f380 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -120,7 +120,8 @@ file(Name, Options) ->
Suffix = proplists:get_value(file_suffix, Options,
?DEFAULT_FILE_SUFFIX),
Dir = proplists:get_value(dir, Options, filename:dirname(Name)),
- edoc_lib:write_file(Text, Dir, BaseName ++ Suffix).
+ Encoding = [{encoding, edoc_lib:read_encoding(Name, [])}],
+ edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, '', Encoding).
%% TODO: better documentation of files/1/2, packages/1/2, application/1/2/3
@@ -455,14 +456,14 @@ expand_sources(Ss, Opts) ->
end,
expand_sources(Ss1, Suffix, sets:new(), [], []).
-expand_sources([{P, F, D} | Fs], Suffix, S, As, Ms) ->
- M = list_to_atom(packages:concat(P, filename:rootname(F, Suffix))),
+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, P, F, D} | As],
+ expand_sources(Fs, Suffix, S1, [{M, '', F, D} | As],
[M | Ms])
end;
expand_sources([], _Suffix, _S, As, Ms) ->
diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl
index 98debba4ab..44c5d6fef4 100644
--- a/lib/edoc/src/edoc.hrl
+++ b/lib/edoc/src/edoc.hrl
@@ -48,7 +48,8 @@
%% functions = ordset(function_name()),
%% exports = ordset(function_name()),
%% attributes = ordset({atom(), term()}),
-%% records = [{atom(), [{atom(), term()}]}]}
+%% records = [{atom(), [{atom(), term()}]}],
+%% encoding = epp:source_encoding()}
%% ordset(T) = sets:ordset(T)
%% function_name(T) = {atom(), integer()}
@@ -57,7 +58,8 @@
functions = [],
exports = [],
attributes = [],
- records = []
+ records = [],
+ encoding = latin1
}).
%% Environment for generating documentation data
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index 624f9177a2..f88ba05f4b 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -83,7 +83,8 @@ module(Module, Entries, Env, Opts) ->
AllTags = get_all_tags(Entries),
Functions = function_filter(Entries, Opts),
Out = {module, ([{name, Name},
- {root, Env#env.root}]
+ {root, Env#env.root},
+ {encoding, Module#module.encoding}]
++ case is_private(HeaderTags) of
true -> [{private, "yes"}];
false -> []
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index 385d20e9ae..a0c1ae1c0f 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -192,8 +192,9 @@ source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
andalso ((not is_hidden(Doc)) orelse Hidden) of
true ->
Text = edoc:layout(Doc, Options),
- Name1 = packages:last(M) ++ Suffix,
- edoc_lib:write_file(Text, Dir, Name1, P),
+ Name1 = atom_to_list(M) ++ Suffix,
+ Encoding = [{encoding,encoding(Doc)}],
+ edoc_lib:write_file(Text, Dir, Name1, P, Encoding),
{sets:add_element(Module, Set), Error};
false ->
{Set, Error}
@@ -204,9 +205,9 @@ source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
end.
check_name(M, M0, P0, File) ->
- P = list_to_atom(packages:strip_last(M)),
- N = packages:last(M),
- N0 = packages:last(M0),
+ P = '',
+ N = M,
+ N0 = M0,
case N of
[$? | _] ->
%% A module name of the form '?...' is assumed to be caused
@@ -359,14 +360,19 @@ xhtml_1(Title, CSS, Body) ->
overview(Dir, Title, Env, Opts) ->
File = proplists:get_value(overview, Opts,
filename:join(Dir, ?OVERVIEW_FILE)),
+ Encoding = edoc_lib:read_encoding(File, [{in_comment_only, false}]),
Tags = read_file(File, overview, Env, Opts),
- Data = edoc_data:overview(Title, Tags, Env, Opts),
+ Data0 = edoc_data:overview(Title, Tags, Env, Opts),
+ EncodingAttribute = #xmlAttribute{name = encoding,
+ value = atom_to_list(Encoding)},
+ #xmlElement{attributes = As} = Data0,
+ Data = Data0#xmlElement{attributes = [EncodingAttribute | As]},
F = fun (M) ->
M:overview(Data, Opts)
end,
Text = edoc_lib:run_layout(F, Opts),
- edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY).
-
+ EncOpts = [{encoding,Encoding}],
+ edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, '', EncOpts).
copy_image(Dir) ->
case code:priv_dir(?EDOC_APP) of
@@ -441,6 +447,12 @@ is_hidden(E) ->
_ -> false
end.
+encoding(E) ->
+ case get_attrval(encoding, E) of
+ "latin1" -> latin1;
+ _ -> utf8
+ end.
+
get_attrval(Name, #xmlElement{attributes = As}) ->
case get_attr(Name, As) of
[#xmlAttribute{value = V}] ->
diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl
index 5a79e127f6..67a95e80aa 100644
--- a/lib/edoc/src/edoc_extract.erl
+++ b/lib/edoc/src/edoc_extract.erl
@@ -121,7 +121,7 @@ source1(Tree, File0, Env, Opts, TypeDocs) ->
Module = get_module_info(Tree, File),
{Header, Footer, Entries} = collect(Forms, Module),
Name = Module#module.name,
- Package = list_to_atom(packages:strip_last(Name)),
+ Package = '',
Env1 = Env#env{module = Name,
package = Package,
root = edoc_refs:relative_package_path('', Package)},
@@ -226,7 +226,7 @@ add_macro_defs(Defs0, Opts, Env) ->
%% lines of text before the first tag are ignored. `Env' is an
%% environment created by {@link edoc_lib:get_doc_env/4}. Upon error,
%% `Reason' is an atom returned from the call to {@link
-%% //kernel/file:read_file/1}.
+%% //kernel/file:read_file/1} or the atom 'invalid_unicode'.
%%
%% See {@link text/4} for options.
@@ -235,7 +235,13 @@ add_macro_defs(Defs0, Opts, Env) ->
file(File, Context, Env, Opts) ->
case file:read_file(File) of
{ok, Bin} ->
- {ok, text(binary_to_list(Bin), Context, Env, Opts, File)};
+ Enc = edoc_lib:read_encoding(File,[{in_comment_only, false}]),
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, text(String, Context, Env, Opts, File)};
+ _ ->
+ {error, invalid_unicode}
+ end;
{error, _} = Error ->
Error
end.
@@ -306,12 +312,14 @@ get_module_info(Forms, File) ->
Exports = ordsets:from_list(get_list_keyval(exports, L)),
Attributes = ordsets:from_list(get_list_keyval(attributes, L)),
Records = get_list_keyval(records, L),
+ Encoding = edoc_lib:read_encoding(File, []),
#module{name = Name,
parameters = Vars,
functions = Functions,
exports = ordsets:intersection(Exports, Functions),
attributes = Attributes,
- records = Records}.
+ records = Records,
+ encoding = Encoding}.
get_list_keyval(Key, L) ->
case lists:keyfind(Key, 1, L) of
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 951cec121c..7bd0615f5c 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -210,7 +210,8 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
++ [hr, ?NL]
++ navigation("bottom")
++ timestamp()),
- xhtml(Title, stylesheet(Opts), Body).
+ Encoding = get_attrval(encoding, E),
+ xhtml(Title, stylesheet(Opts), Body, Encoding).
module_params(Es) ->
As = [{get_text(argName, Es1),
@@ -956,10 +957,17 @@ 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";
+ _ -> "UTF-8"
+ end,
[{html, [?NL,
{head, [?NL,
{meta, [{'http-equiv',"Content-Type"},
- {content, "text/html; charset=ISO-8859-1"}],
+ {content, "text/html; charset="++EncString}],
[]},
?NL,
{title, Title},
@@ -1021,7 +1029,8 @@ overview(E=#xmlElement{name = overview, content = Es}, Options) ->
++ [?NL, hr]
++ navigation("bottom")
++ timestamp()),
- XML = xhtml(Title, stylesheet(Opts), Body),
+ Encoding = get_attrval(encoding, E),
+ XML = xhtml(Title, stylesheet(Opts), Body, Encoding),
xmerl:export_simple(XML, ?HTML_EXPORT, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% NYTT
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index 90fb8a679c..3d193c4bfa 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% =====================================================================
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
@@ -30,10 +31,10 @@
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_info_file/4,
+ 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,
uri_get/1, run_doclet/2, run_layout/2,
- simplify_path/1, timestr/1, datestr/1]).
+ simplify_path/1, timestr/1, datestr/1, read_encoding/2]).
-import(edoc_report, [report/2, warning/2]).
@@ -57,6 +58,13 @@ datestr({Y,M,D}) ->
lists:flatten(io_lib:fwrite("~s ~w ~w",[lists:nth(M, Ms),D,Y])).
%% @private
+read_encoding(File, Options) ->
+ case epp:read_encoding(File, Options) of
+ none -> epp:default_encoding();
+ Encoding -> Encoding
+ end.
+
+%% @private
count(X, Xs) ->
count(X, Xs, 0).
@@ -228,13 +236,13 @@ end_of_sentence_1(_, false, _) ->
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%% Names must begin with a lowercase letter and contain only
%% alphanumerics and underscores.
@@ -261,6 +269,10 @@ 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)];
@@ -677,7 +689,6 @@ try_subdir(Dir, Subdir) ->
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
@@ -685,10 +696,12 @@ write_file(Text, Dir, Name) ->
%% @private
write_file(Text, Dir, Name, Package) ->
- Dir1 = filename:join([Dir | packages:split(Package)]),
- File = filename:join(Dir1, Name),
+ write_file(Text, Dir, Name, Package, [{encoding,latin1}]).
+
+write_file(Text, Dir, Name, Package, Options) ->
+ File = filename:join([Dir, to_list(Package), Name]),
ok = filelib:ensure_dir(File),
- case file:open(File, [write]) of
+ case file:open(File, [write] ++ Options) of
{ok, FD} ->
io:put_chars(FD, Text),
ok = file:close(FD);
@@ -705,8 +718,9 @@ write_info_file(App, Packages, Modules, Dir) ->
Ts1 = if App =:= ?NO_APP -> Ts;
true -> [{application, App} | Ts]
end,
- S = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
- write_file(S, Dir, ?INFO_FILE).
+ S0 = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
+ S = ["%% encoding: UTF-8\n" | S0],
+ write_file(S, Dir, ?INFO_FILE, '', [{encoding,unicode}]).
%% @spec (Name::edoc:filename()) -> {ok, string()} | {error, Reason}
%%
@@ -714,7 +728,14 @@ write_info_file(App, Packages, Modules, Dir) ->
read_file(File) ->
case file:read_file(File) of
- {ok, Bin} -> {ok, binary_to_list(Bin)};
+ {ok, Bin} ->
+ Enc = edoc_lib:read_encoding(File, []),
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, String};
+ _ ->
+ {error, invalid_unicode}
+ end;
{error, Reason} -> {error, Reason}
end.
@@ -818,7 +839,7 @@ find_sources(Path, Pkg, Rec, Ext, Opts) ->
lists:flatten(find_sources_1(Path, to_atom(Pkg), Rec, Ext, Skip)).
find_sources_1([P | Ps], Pkg, Rec, Ext, Skip) ->
- Dir = filename:join(P, filename:join(packages:split(Pkg))),
+ Dir = filename:join(P, atom_to_list(Pkg)),
Fs1 = find_sources_1(Ps, Pkg, Rec, Ext, Skip),
case filelib:is_dir(Dir) of
true ->
@@ -844,9 +865,9 @@ find_sources_2(Dir, Pkg, Rec, Ext, Skip) ->
[]
end.
-find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) ->
+find_sources_3(Es, Dir, '', Rec, Ext, Skip) ->
[find_sources_2(filename:join(Dir, E),
- to_atom(packages:concat(Pkg, E)), Rec, Ext, Skip)
+ to_atom(E), Rec, Ext, Skip)
|| E <- Es, is_package_dir(E, Dir)].
is_source_file(Name, Ext) ->
@@ -858,16 +879,16 @@ is_package_dir(Name, Dir) ->
andalso filelib:is_dir(filename:join(Dir, Name)).
%% @private
-find_file([P | Ps], Pkg, Name) ->
- Dir = filename:join(P, filename:join(packages:split(Pkg))),
- File = filename:join(Dir, Name),
+find_file([P | Ps], []=Pkg, Name) ->
+ Pkg = [],
+ File = filename:join(P, Name),
case filelib:is_file(File) of
true ->
File;
false ->
find_file(Ps, Pkg, Name)
end;
-find_file([], _Pkg, _Name) ->
+find_file([], [], _Name) ->
"".
%% @private
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index 70fb38bf0a..08686c4fb5 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -88,13 +88,13 @@ link_macro(S, Line, Env) ->
true -> " target=\"_top\""; % note the initial space
false -> ""
end,
- lists:flatten(io_lib:fwrite("<a href=\"~s\"~s>~s</a>",
+ lists:flatten(io_lib:fwrite("<a href=\"~s\"~s>~ts</a>",
[URI, Target, Txt])).
section_macro(S, _Line, _Env) ->
S1 = lists:reverse(edoc_lib:strip_space(
lists:reverse(edoc_lib:strip_space(S)))),
- lists:flatten(io_lib:format("<a href=\"#~s\">~s</a>",
+ lists:flatten(io_lib:format("<a href=\"#~ts\">~ts</a>",
[edoc_lib:to_label(S1), S1])).
type_macro(S, Line, Env) ->
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index 4d6428f75b..cf1a2d6b11 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -1,6 +1,7 @@
+%% -*- coding: utf-8 -*-
%% ========================== -*-Erlang-*- =============================
%% EDoc type specification grammar for the Yecc parser generator,
-%% adapted from Sven-Olof Nystr�m's type specification parser.
+%% adapted from Sven-Olof Nyström's type specification parser.
%%
%% Also contains entry points for parsing things like typedefs,
%% references, and throws-declarations.
@@ -100,9 +101,7 @@ ptype -> '[' utype ',' '...' ']' : #t_nonempty_list{type = '$2'}.
ptype -> utype_list:
if length(element(1, '$1')) == 1 ->
%% there must be exactly one utype in the list
- hd(element(1, '$1'));
- %% Replace last line when releasing next major release:
- %% #t_paren{type = hd(element(1, '$1'))};
+ #t_paren{type = hd(element(1, '$1'))};
length(element(1, '$1')) == 0 ->
return_error(element(2, '$1'), "syntax error before: ')'");
true ->
@@ -319,10 +318,7 @@ tok_val(T) -> element(3, T).
tok_line(T) -> element(2, T).
-qname([A]) ->
- A; % avoid unnecessary call to packages:concat/1.
-qname(List) ->
- list_to_atom(packages:concat(lists:reverse(List))).
+qname([A]) -> A.
union(Ts) ->
case Ts of
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
index 1f578a3b83..ea439490ed 100644
--- a/lib/edoc/src/edoc_refs.erl
+++ b/lib/edoc/src/edoc_refs.erl
@@ -126,7 +126,7 @@ abs_uri({package, P}, Env) ->
module_ref(M, Env) ->
case (Env#env.modules)(M) of
"" ->
- File = packages:last(M) ++ Env#env.file_suffix,
+ File = atom_to_list(M) ++ Env#env.file_suffix,
Path = relative_module_path(M, Env#env.package),
join_uri(Path, escape_uri(File));
Base ->
@@ -134,8 +134,7 @@ module_ref(M, Env) ->
end.
module_absref(M, Env) ->
- join_segments(packages:split(M))
- ++ escape_uri(Env#env.file_suffix).
+ escape_uri(atom_to_list(M)) ++ escape_uri(Env#env.file_suffix).
package_ref(P, Env) ->
case (Env#env.packages)(P) of
@@ -147,7 +146,7 @@ package_ref(P, Env) ->
end.
package_absref(P, Env) ->
- join_uri(join_segments(packages:split(P)),
+ join_uri(escape_uri(atom_to_list(P)),
escape_uri(Env#env.package_summary)).
app_ref(A, Env) ->
@@ -179,14 +178,11 @@ join_segments([S | Ss]) ->
%% The empty string is returned if the To module has only one segment,
%% implying a local reference.
-relative_module_path(To, From) ->
- case first(packages:split(To)) of
- [] -> "";
- P -> relative_path(P, packages:split(From))
- end.
+relative_module_path(_To, _From) ->
+ "".
relative_package_path(To, From) ->
- relative_path(packages:split(To), packages:split(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
@@ -210,6 +206,3 @@ relative_path_2([], []) ->
"";
relative_path_2([], Ts) ->
join_segments(Ts).
-
-first([H | T]) when T /= [] -> [H | first(T)];
-first(_) -> [].
diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl
index 5c71658af5..cc0529d2a9 100644
--- a/lib/edoc/src/edoc_wiki.erl
+++ b/lib/edoc/src/edoc_wiki.erl
@@ -80,6 +80,7 @@ parse_xml(Data, Line) ->
parse_xml_1(Text, Line) ->
Text1 = "<doc>" ++ Text ++ "</doc>",
+ %% Any coding except "utf-8".
Opts = [{line, Line}, {encoding, 'iso-8859-1'}],
case catch {ok, xmerl_scan:string(Text1, Opts)} of
{ok, {E, _}} ->
@@ -174,7 +175,7 @@ expand_heading_1(Cs, N, L, As) ->
expand_heading_2(Ts, Cs, N, L, As) ->
H = ?BASE_HEADING + N,
- Ts1 = io_lib:format("<h~w><a name=\"~s\">~s</a></h~w>\n",
+ Ts1 = io_lib:format("<h~w><a name=\"~ts\">~ts</a></h~w>\n",
[H, make_label(Ts), Ts, H]),
expand_new_line(Cs, L + 1, lists:reverse(lists:flatten(Ts1), As)).