aboutsummaryrefslogtreecommitdiffstats
path: root/lib/docbuilder/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/docbuilder/src')
-rw-r--r--lib/docbuilder/src/Makefile121
-rw-r--r--lib/docbuilder/src/docb_edoc_xml_cb.erl1163
-rw-r--r--lib/docbuilder/src/docb_gen.erl138
-rw-r--r--lib/docbuilder/src/docb_html.erl394
-rw-r--r--lib/docbuilder/src/docb_html_layout.erl380
-rw-r--r--lib/docbuilder/src/docb_html_ref.erl79
-rw-r--r--lib/docbuilder/src/docb_html_util.erl543
-rw-r--r--lib/docbuilder/src/docb_html_util_iso.erl204
-rw-r--r--lib/docbuilder/src/docb_main.erl651
-rw-r--r--lib/docbuilder/src/docb_pretty_format.erl177
-rw-r--r--lib/docbuilder/src/docb_tr_application2html.erl288
-rw-r--r--lib/docbuilder/src/docb_tr_appref2html.erl48
-rw-r--r--lib/docbuilder/src/docb_tr_chapter2html.erl59
-rw-r--r--lib/docbuilder/src/docb_tr_cite2html.erl136
-rw-r--r--lib/docbuilder/src/docb_tr_comref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_cref2html.erl61
-rw-r--r--lib/docbuilder/src/docb_tr_erlref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_fileref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_first2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_index2html.erl197
-rw-r--r--lib/docbuilder/src/docb_tr_part2html.erl240
-rw-r--r--lib/docbuilder/src/docb_tr_refs2kwic.erl156
-rw-r--r--lib/docbuilder/src/docb_tr_report2html.erl70
-rw-r--r--lib/docbuilder/src/docb_tr_term2html.erl126
-rw-r--r--lib/docbuilder/src/docb_transform.erl161
-rw-r--r--lib/docbuilder/src/docb_util.erl237
-rw-r--r--lib/docbuilder/src/docb_util.hrl34
-rw-r--r--lib/docbuilder/src/docb_xmerl_tree_cb.erl343
-rw-r--r--lib/docbuilder/src/docb_xmerl_xml_cb.erl88
-rw-r--r--lib/docbuilder/src/docb_xml_check.erl44
-rw-r--r--lib/docbuilder/src/docbuilder.app.src37
-rw-r--r--lib/docbuilder/src/docbuilder.appup.src1
32 files changed, 6360 insertions, 0 deletions
diff --git a/lib/docbuilder/src/Makefile b/lib/docbuilder/src/Makefile
new file mode 100644
index 0000000000..e8a07a54e8
--- /dev/null
+++ b/lib/docbuilder/src/Makefile
@@ -0,0 +1,121 @@
+# ``The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved via the world wide web at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+# Portions created by Ericsson are Copyright 1999-2000, Ericsson
+# Utvecklings AB. All Rights Reserved.''
+#
+# $Id$
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(DOCB_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/docbuilder-$(VSN)
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+MODULES= \
+ docb_edoc_xml_cb \
+ docb_gen \
+ docb_html \
+ docb_html_layout \
+ docb_html_ref \
+ docb_html_util \
+ docb_html_util_iso \
+ docb_main \
+ docb_pretty_format \
+ docb_tr_application2html \
+ docb_tr_appref2html \
+ docb_tr_chapter2html \
+ docb_tr_cite2html \
+ docb_tr_comref2html \
+ docb_tr_cref2html \
+ docb_tr_erlref2html \
+ docb_tr_fileref2html \
+ docb_tr_first2html \
+ docb_tr_index2html \
+ docb_tr_part2html \
+ docb_tr_refs2kwic \
+ docb_tr_report2html \
+ docb_tr_term2html \
+ docb_transform \
+ docb_util \
+ docb_xmerl_tree_cb \
+ docb_xmerl_xml_cb \
+ docb_xml_check
+
+HRL_FILES= \
+ docb_util.hrl
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+APP_FILE= docbuilder.app
+APPUP_FILE= docbuilder.appup
+APP_SRC= $(APP_FILE).src
+APPUP_SRC= $(APPUP_FILE).src
+APP_TARGET= $(EBIN)/$(APP_FILE)
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_FLAGS +=
+XMERL = ../../xmerl
+ERL_COMPILE_FLAGS += -I$(XMERL)/include
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET)
+ rm -f errs core *~
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+
+release_docs_spec:
+
+
+
+
+
diff --git a/lib/docbuilder/src/docb_edoc_xml_cb.erl b/lib/docbuilder/src/docb_edoc_xml_cb.erl
new file mode 100644
index 0000000000..4dba843341
--- /dev/null
+++ b/lib/docbuilder/src/docb_edoc_xml_cb.erl
@@ -0,0 +1,1163 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the Licence for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
+%% All Rights Reserved.��
+%%
+%% $Id$
+%%
+-module(docb_edoc_xml_cb).
+
+%% This is the EDoc callback module for creating DocBuilder erlref
+%% documents (man pages) in XML format, and also a DocBuilder chapter
+%% document based on "overview.edoc".
+%%
+%% Usage examples:
+%% docb_gen File
+%% docb_gen -chapter overview.edoc
+%% or (from an Erlang shell)
+%% edoc:file(File, [{layout,docb_edoc_xml_cb},{file_suffix,".xml"},
+%% {preprocess,true}]).
+%%
+%% The origin of this file is the edoc module otpsgml_layout.erl
+%% written by Richard Carlsson.
+
+-export([module/2, overview/2]).
+
+-include("xmerl.hrl").
+
+-define(NL, "\n").
+
+%%-User interface-------------------------------------------------------
+
+%% ERLREF
+module(Element, Opts) ->
+ SortP = proplists:get_value(sort_functions, Opts, true),
+ XML = layout_module(Element, SortP),
+ xmerl:export_simple([XML], docb_xmerl_xml_cb, []).
+
+%% CHAPTER
+overview(Element, _Opts) ->
+ XML = layout_chapter(Element),
+ xmerl:export_simple([XML], docb_xmerl_xml_cb, []).
+
+%%--Internal functions--------------------------------------------------
+
+layout_module(#xmlElement{name = module, content = Es}=E, SortP) ->
+ Name = get_attrval(name, E),
+ Desc = get_content(description, Es),
+ ShortDesc = text_only(get_content(briefDescription, Desc)),
+ FullDesc = otp_xmlify(get_content(fullDescription, Desc)),
+ Types0 = get_content(typedecls, Es),
+ Types1 = lists:sort([{type_name(Et), Et} || Et <- Types0]),
+ Functions =
+ case SortP of
+ true ->
+ lists:sort([{function_name(Ef), Ef} ||
+ Ef <- get_content(functions, Es)]);
+ false ->
+ [{function_name(Ef), Ef} ||
+ Ef <- get_content(functions, Es)]
+ end,
+ Header = {header, [
+ ?NL,{title, [Name]},
+ ?NL,{prepared, [""]},
+ ?NL,{responsible, [""]},
+ ?NL,{docno, ["1"]},
+ ?NL,{approved, [""]},
+ ?NL,{checked, [""]},
+ ?NL,{date, [""]},
+ ?NL,{rev, ["A"]},
+ ?NL,{file, [Name++".xml"]}
+ ]},
+ Module = {module, [Name]},
+ ModuleSummary = {modulesummary, ShortDesc},
+ Description = {description, [?NL|FullDesc]},
+ Types = case Types1 of
+ [] -> [];
+ _ ->
+ [?NL, {section,[{title,["DATA TYPES"]},
+ {marker,[{id,"types"}],[]},
+ ?NL|types(Types1)]}]
+ end,
+ Funcs = functions(Functions),
+ See = seealso_module(Es),
+ Authors = {authors, authors(Es)},
+ {erlref,
+ [?NL,Header,
+ ?NL,Module,
+ ?NL,ModuleSummary,
+ ?NL,Description]
+ ++ Types ++
+ [?NL,Funcs,
+ ?NL,See,
+ ?NL,Authors]
+ }.
+
+layout_chapter(#xmlElement{name=overview, content=Es}) ->
+ Title = get_text(title, Es),
+ Header = {header, [
+ ?NL,{title,[Title]},
+ ?NL,{prepared,[""]},
+ ?NL,{docno,[""]},
+ ?NL,{date,[""]},
+ ?NL,{rev,[""]},
+ ?NL,{file, ["chapter.xml"]}
+ ]},
+ DescEs = get_content(description, Es),
+ FullDescEs = get_content(fullDescription, DescEs),
+ Sections = chapter_ify(FullDescEs, first),
+ {chapter, [?NL, Header, ?NL | Sections]}.
+
+chapter_ify([], _) ->
+ [];
+chapter_ify(Es, first) ->
+ %% Everything up to the first section should be made into
+ %% plain paragraphs -- or if no first section is found, everything
+ %% should be made into one
+ case find_next(h3, Es) of
+ {Es, []} ->
+ SubSections = subchapter_ify(Es, first),
+ [{section, [?NL,{title,["Overview"]},
+ ?NL | SubSections]}];
+ {FirstEs, RestEs} ->
+ otp_xmlify(FirstEs) ++ chapter_ify(RestEs, next)
+ end;
+chapter_ify([#xmlElement{name=h3} = E | Es], next) ->
+ {SectionEs, RestEs} = find_next(h3, Es),
+ SubSections = subchapter_ify(SectionEs, first),
+ {Marker, Title} = chapter_title(E),
+ [{section, [?NL,{marker,[{id,Marker}],[]},
+ ?NL,{title,[Title]},
+ ?NL | SubSections]} | chapter_ify(RestEs, next)].
+
+subchapter_ify([], _) ->
+ [];
+subchapter_ify(Es, first) ->
+ %% Everything up to the (possible) first subsection should be
+ %% made into plain paragraphs
+ {FirstEs, RestEs} = find_next(h4, Es),
+ otp_xmlify(FirstEs) ++ subchapter_ify(RestEs, next);
+subchapter_ify([#xmlElement{name=h4} = E | Es], next) ->
+ {SectionEs, RestEs} = find_next(h4, Es),
+ Elements = otp_xmlify(SectionEs),
+ {Marker, Title} = chapter_title(E),
+ [{section, [?NL,{marker,[{id,Marker}],[]},
+ ?NL,{title,[Title]},
+ ?NL | Elements]} | subchapter_ify(RestEs, next)].
+
+chapter_title(#xmlElement{content=Es}) -> % name = h3 | h4
+ case Es of
+ [#xmlElement{name=a} = E] ->
+ {get_attrval(name, E), get_text(E)}
+ end.
+
+%%--XHTML->XML transformation-------------------------------------------
+
+%% otp_xmlify(Es1) -> Es2
+%% Es1 = Es2 = [#xmlElement{} | #xmlText{}]
+%% Fix things that are allowed in XHTML but not in chapter/erlref DTDs.
+%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) can not occur
+%% within a <p>, such a <p> must be splitted into a sequence of <p>,
+%% <ul>, <ol>, <dl> and <pre>.
+%% 2) <a> must only have either a href attribute (corresponds to a
+%% <seealso> or <url> in the XML code) in which case its content
+%% must be plain text; or a name attribute (<marker>).
+%% 3a) <b> content must be plain text.
+%% b) <em> content must be plain text (or actually a <code> element
+%% as well, but a simplification is used here).
+%% c) <pre> content must be plain text (or could actually contain
+%% <input> as well, but a simplification is used here).
+%% 4) <code> content must be plain text, or the element must be split
+%% into a list of elements.
+%% 5a) <h1>, <h2> etc is not allowed - replaced by its content within
+%% a <b> tag.
+%% b) <center> is not allowed - replaced by its content.
+%% c) <font> -"-
+%% 6) <table> is not allowed in erlref, translated to text instead.
+%% Also a <table> in chapter without a border is translated to text.
+%% A <table> in chapter with a border must contain a <tcaption>.
+%% 7) <sup> is not allowed - is replaced with its text content
+%% within parenthesis.
+%% 8) <blockquote> contents may need to be made into paragraphs
+%% 9) <th> (table header) is not allowed - is replaced by
+%% <td><em>...</em></td>.
+otp_xmlify([]) ->
+ [];
+otp_xmlify(Es0) ->
+ Es = case is_paragraph(hd(Es0)) of
+
+ %% If the first element is a <p> xmlElement, then
+ %% the entire element list is ready to be otp_xmlified.
+ true ->
+ Es0;
+
+ %% If the first element is not a <p> xmlElement, then all
+ %% elements up to the first <p> (or end of list) must be
+ %% made into a paragraph (using the {p, Es} construction)
+ %% before the list is otp_xmlified.
+ false ->
+ case find_next(p, Es0, []) of
+ {[#xmlText{value=Str}] = First, Rest} ->
+ %% Special case: Making a paragraph out of a
+ %% blank line isn't a great idea.
+ case is_empty(Str) of
+ true ->
+ Rest;
+ false ->
+ [{p,First}|Rest]
+ end;
+ {First, Rest} ->
+ [{p,First}|Rest]
+ end
+ end,
+
+ %% Fix paragraph breaks not needed in XHTML but in XML
+ EsFixed = otp_xmlify_fix(Es),
+
+ otp_xmlify_es(EsFixed).
+
+%% EDoc does not always translate empty lines (with leading "%%")
+%% as paragraph break, this is the fix
+otp_xmlify_fix(Es) ->
+ otp_xmlify_fix(Es, []).
+otp_xmlify_fix([#xmlText{value="\n \n"++_} = E1, E2 | Es], Res) ->
+ %% This is how it looks when generating an erlref from a .erl file
+ case is_paragraph(E2) of
+ false ->
+ {P, After} = find_p_ending(Es, []),
+ otp_xmlify_fix(After, [{p, [E2|P]}, E1 | Res]);
+ true ->
+ otp_xmlify_fix([E2|Es], [E1|Res])
+ end;
+otp_xmlify_fix([#xmlText{value="\n\n"} = E1, E2 | Es], Res) ->
+ %% This is how it looks when generating a chapter from overview.edoc
+ case is_paragraph(E2) of
+ false ->
+ {P, After} = find_p_ending(Es, []),
+ otp_xmlify_fix(After, [{p, [E2|P]}, E1 | Res]);
+ true ->
+ otp_xmlify_fix([E2|Es], [E1|Res])
+ end;
+otp_xmlify_fix([E|Es], Res) ->
+ otp_xmlify_fix(Es, [E|Res]);
+otp_xmlify_fix([], Res) ->
+ lists:reverse(Res).
+
+otp_xmlify_es([E | Es]) ->
+ case is_paragraph(E) of
+ true ->
+ case otp_xmlify_psplit(E) of
+
+ %% paragraph contained inline tags and text only
+ nosplit ->
+ otp_xmlify_e(E) ++ otp_xmlify_es(Es);
+
+ %% paragraph contained dl, ul and/or pre and has been
+ %% splitted
+ SubEs ->
+ lists:flatmap(fun otp_xmlify_e/1, SubEs) ++
+ otp_xmlify_es(Es)
+ end;
+ false ->
+ otp_xmlify_e(E) ++ otp_xmlify_es(Es)
+ end;
+otp_xmlify_es([]) ->
+ [].
+
+%% otp_xmlify_psplit(P) -> nosplit | [E]
+%% Handles case 1) above.
+%% Uses the {p, Es} construct, thus replaces an p xmlElement with one
+%% or more {p, Es} tuples if splitting the paraghrap is necessary.
+otp_xmlify_psplit(P) ->
+ otp_xmlify_psplit(p_content(P), [], []).
+otp_xmlify_psplit([#xmlElement{name=Name}=E | Es], Content, Res) ->
+ if
+ Name==blockquote; Name==ul; Name==ol; Name==dl; Name==pre;
+ Name==table ->
+ case Content of
+ [] ->
+ otp_xmlify_psplit(Es, [], [E|Res]);
+ [#xmlText{value=Str}] ->
+ %% Special case: Making a paragraph out of a blank
+ %% line isn't a great idea. Instead, this can be
+ %% viewed as the case above, where there is no
+ %% content to make a paragraph out of
+ case is_empty(Str) of
+ true ->
+ otp_xmlify_psplit(Es, [], [E|Res]);
+ false ->
+ Pnew = {p, lists:reverse(Content)},
+ otp_xmlify_psplit(Es, [], [E,Pnew|Res])
+ end;
+ _ ->
+ Pnew = {p, lists:reverse(Content)},
+ otp_xmlify_psplit(Es, [], [E,Pnew|Res])
+ end;
+
+ true ->
+ otp_xmlify_psplit(Es, [E|Content], Res)
+ end;
+otp_xmlify_psplit([E | Es], Content, Res) ->
+ otp_xmlify_psplit(Es, [E|Content], Res);
+otp_xmlify_psplit([], _Content, []) ->
+ nosplit;
+otp_xmlify_psplit([], [], Res) ->
+ lists:reverse(Res);
+otp_xmlify_psplit([], [#xmlText{value="\n\n"}], Res) ->
+ lists:reverse(Res);
+otp_xmlify_psplit([], Content, Res) ->
+ Pnew = {p, lists:reverse(Content)},
+ lists:reverse([Pnew|Res]).
+
+%% otp_xmlify_e(E) -> [E]
+%% This is the function which does the actual transformation of
+%% single elements, normally by making sure the content corresponds
+%% to what is allowed by the OTP DTDs.
+%% Returns a list of elements as the xmlification in some cases
+%% returns no element or more than one element (although in most cases
+%% exactly one element).
+otp_xmlify_e(#xmlElement{name=a} = E) -> % 2) above
+ otp_xmlify_a(E);
+otp_xmlify_e(#xmlElement{name=Tag} = E) % 3a-c)
+ when Tag==b; Tag==em; Tag==pre ->
+ Content = text_only(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=code} = E) -> % 4)
+ case catch text_only(E#xmlElement.content) of
+ {'EXIT', _Error} ->
+ otp_xmlify_code(E);
+ Content ->
+ [E#xmlElement{content=Content}]
+ end;
+otp_xmlify_e(#xmlElement{name=Tag} = E) % 5a
+ when Tag==h1; Tag==h2; Tag==h3; Tag==h4; Tag==h5;
+ Tag==center;
+ Tag==font ->
+ Content = text_only(E#xmlElement.content),
+ [E#xmlElement{name=b, content=Content}];
+otp_xmlify_e(#xmlElement{name=Tag} = E) % 5b-c)
+ when Tag==center;
+ Tag==font ->
+ otp_xmlify_e(E#xmlElement.content);
+otp_xmlify_e(#xmlElement{name=table} = E) -> % 6)
+ case parent(E) of
+ module ->
+ otp_xmlify_table(E#xmlElement.content);
+ overview ->
+ case get_attrval(border, E) of
+ "" -> % implies border="0"
+ [{p, otp_xmlify_table(E#xmlElement.content)}];
+ "0" ->
+ [{p, otp_xmlify_table(E#xmlElement.content)}];
+ _Val ->
+ Content0 = otp_xmlify_e(E#xmlElement.content),
+ Summary = #xmlText{value=get_attrval(summary, E)},
+ TCaption = E#xmlElement{name=tcaption,
+ attributes=[],
+ content=[Summary]},
+ Content = Content0 ++ [TCaption],
+ [E#xmlElement{attributes=[], content=Content}]
+ end
+ end;
+otp_xmlify_e(#xmlElement{name=sup} = E) -> % 7)
+ Text = get_text(E),
+ [#xmlText{parents = E#xmlElement.parents,
+ pos = E#xmlElement.pos,
+ language = E#xmlElement.language,
+ value = "(" ++ Text ++ ")"}];
+otp_xmlify_e(#xmlElement{name=blockquote} = E) -> % 8)
+ Content = otp_xmlify_blockquote(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=th} = E) -> % 9)
+ Content = otp_xmlify_e(E#xmlElement.content),
+ EmE = E#xmlElement{name=em, content=Content},
+ [E#xmlElement{name=td, content=[EmE]}];
+otp_xmlify_e(#xmlElement{name=p} = E) -> % recurse
+ Content = otp_xmlify_e(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e({p, Content1}) ->
+ Content2 = otp_xmlify_e(Content1),
+ [{p, Content2}];
+otp_xmlify_e(#xmlElement{name=ul} = E) ->
+ Content = otp_xmlify_e(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=li} = E) ->
+ %% Content may need to be made into <p>s etc.
+ Content = otp_xmlify(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=dl} = E) ->
+ Content0 = otp_xmlify_e(E#xmlElement.content),
+ Content = otp_xmlify_dl(Content0),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=dt} = E) ->
+ %% Special fix: Markers in <taglist> <tag>s are not allowed,
+ %% save it using 'put' and place the marker first in the <item>
+ %% instead
+ Content = case E#xmlElement.content of
+ [#xmlElement{name=a} = A] ->
+ put(dt_marker, otp_xmlify_e(A)),
+ otp_xmlify_e(A#xmlElement.content);
+ _ ->
+ otp_xmlify_e(E#xmlElement.content)
+ end,
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=dd} = E) ->
+ %% Content may need to be made into <p>s etc.
+ Content0 = otp_xmlify(E#xmlElement.content),
+ Content = case get(dt_marker) of
+ undefined -> Content0;
+ [Marker] ->
+ put(dt_marker, undefined),
+ [Marker#xmlElement{content=[]}|Content0]
+ end,
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=tr} = E) ->
+ Content = otp_xmlify_e(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e(#xmlElement{name=td} = E) ->
+ Content = otp_xmlify_e(E#xmlElement.content),
+ [E#xmlElement{content=Content}];
+otp_xmlify_e([E | Es]) ->
+ otp_xmlify_e(E) ++ otp_xmlify_e(Es);
+otp_xmlify_e([]) ->
+ [];
+otp_xmlify_e(E) ->
+ [E].
+
+%%--Tags with special handling------------------------------------------
+
+%% otp_xmlify_a(A1) -> [A2]
+%% Takes an <a> element and filters the attributes to decide wheather
+%% its a seealso/url or a marker.
+%% In the case of a seealso/url, the href part is checked, making
+%% sure a .xml/.html file extension is removed (as DocBuilder inserts
+%% .html extension when resolving cross references).
+%% Also, references to other applications //App has a href attribute
+%% value "OTPROOT/..." (due to app_default being set to "OTPROOT" in
+%% docb_gen.erl), in this case both href attribute and content must be
+%% formatted correctly according to DocBuilder requirements.
+otp_xmlify_a(A) ->
+ [Attr0] = filter_a_attrs(A#xmlElement.attributes),
+ case Attr0 of
+ #xmlAttribute{name=href, value=Href0} -> % seealso | url
+ Content0 = text_only(A#xmlElement.content),
+ {Href, Content} = otp_xmlify_a_href(Href0, Content0),
+ [A#xmlElement{attributes=[Attr0#xmlAttribute{value=Href}],
+ content=Content}];
+ #xmlAttribute{name=name} -> % marker
+ Content = otp_xmlify_e(A#xmlElement.content),
+ [A#xmlElement{attributes=[Attr0], content=Content}]
+ end.
+
+%% filter_a_attrs(Attrs) -> [Attr]
+%% Removes all attributes from a <a> element except the href or
+%% name attribute.
+filter_a_attrs([#xmlAttribute{name=href} = Attr | _Attrs]) ->
+ [Attr];
+filter_a_attrs([#xmlAttribute{name=name} = Attr | _Attrs]) ->
+ [Attr];
+filter_a_attrs([_Attr|Attrs]) ->
+ filter_a_attrs(Attrs);
+filter_a_attrs([]) ->
+ [].
+
+%% otp_xmlify_a_href(Href0, Es0) -> {Href1, Es1}
+%% Href = string()
+otp_xmlify_a_href("#"++_ = Marker, Es0) -> % <seealso marker="#what">
+ {Marker, Es0};
+otp_xmlify_a_href("http:"++_ = URL, Es0) -> % external URL
+ {URL, Es0};
+otp_xmlify_a_href("OTPROOT"++AppRef, Es0) -> % <.. marker="App:FileRef
+ case split(AppRef, "/") of
+ [AppS, "doc", FileRef1] ->
+ FileRef = AppS++":"++otp_xmlify_a_fileref(FileRef1, AppS),
+ [#xmlText{value=Str0} = T] = Es0,
+ Str = case split(Str0, "/") of
+ %% //Application
+ [AppS2] ->
+ %% AppS2 can differ from AppS
+ %% Example: xmerl/XMerL
+ AppS2;
+ [_AppS,ModRef] ->
+ case split(ModRef, ":") of
+ %% //Application/Module
+ [Module] ->
+ Module++"(3)";
+ %% //Application/Module:Type()
+ [_Module,_Type] ->
+ ModRef
+ end;
+ %% //Application/Module:Function/Arity
+ [_AppS,ModFunc,Arity] ->
+ ModFunc++"/"++Arity
+ end,
+ {FileRef, [T#xmlText{value=Str}]}
+ end;
+otp_xmlify_a_href("../"++File, Es0) ->
+ %% Special case: This kind of relative path is used on some
+ %% places within i.e. EDoc and refers to a file within the same
+ %% application tree.
+ %% Correct the path according to the OTP directory structure
+ {"../../"++File, Es0};
+otp_xmlify_a_href(FileRef1, Es0) -> % File within the same application
+ FileRef2 = otp_xmlify_a_fileref(FileRef1, this),
+ {FileRef2, Es0}.
+
+%% otp_xmlify_a_fileref(FileRef1, AppS|this) -> FileRef2
+%% AppS = FileRef = string()
+otp_xmlify_a_fileref(FileRef1, AppS) ->
+ case split(FileRef1, ".#") of
+
+ %% EDoc default name is "overview-summary.html,
+ %% name of OTP User's Guide chapter is "chapter.xml"
+ ["overview-summary", _Ext] ->
+ "chapter";
+ ["overview-summary", _Ext, Marker] ->
+ "chapter#"++Marker;
+
+ [File, Ext] when Ext=="xml";
+ Ext=="html", AppS/=this ->
+ File;
+ [File, Ext, Marker0] ->
+ %% Here is an awkward solution to an awkward problem
+ %% The marker automatically inserted by DocBuilder at
+ %% each function does not seem to work for EDoc generated
+ %% ERLREFs.
+ %% So if the referenced marker is in an ERLREF generated
+ %% by EDoc, keep it "as is", ie "function-arity".
+ %% If the referenced marker is NOT in an ERLREF generated
+ %% by EDoc, the marker should be on the format
+ %% "function/arity".
+ %% The awkward part of the solution is to decide wheather
+ %% the ERLREF is generated by EDoc or not: Here we make
+ %% the decision based on which application the module
+ %% belongs to -- which is ok when the module was written
+ %% but probably not in the future...
+ EDocApps = ["edoc","hipe","syntax_tools","xmerl"],
+ IsEDocGenerated = lists:member(AppS, EDocApps),
+ Marker = if
+ %% The marker is in a file in *this*
+ %% application (which documentation obviously
+ %% is generated by EDoc), or it is in a file
+ %% in an application which documentation
+ %% is assumed to be generated by EDoc
+ AppS==this; IsEDocGenerated ->
+ Marker0;
+
+ %% The marker is in a file in an application
+ %% which documentation is assumed NOT to be
+ %% generated by EDoc
+ true ->
+ case split(Marker0, "-") of
+ [Func,Arity] ->
+ Func++"/"++Arity;
+ _ ->
+ Marker0
+ end
+ end,
+ if
+ %% Ignore file extension in file reference if it either
+ %% is ".xml" or if it is ".html" but AppS/=this, that
+ %% is, we're resolving an OTPROOT file reference
+ Ext=="xml";
+ Ext=="html", AppS/=this ->
+ File++"#"++Marker;
+ true ->
+ File++"."++Ext++"#"++Marker
+ end;
+
+ %% References to other files than XML files are kept as-is
+ _ ->
+ FileRef1
+ end.
+
+%% otp_xmlify_blockquote(Es1) -> Es2
+%% Ensures that the content of a <blockquote> is divided into
+%% <p>s using the {p, Es} construct.
+otp_xmlify_blockquote([#xmlElement{name=p} = E|Es]) ->
+ [E | otp_xmlify_blockquote(Es)];
+otp_xmlify_blockquote([#xmlText{} = E|Es]) ->
+ {P, After} = find_p_ending(Es, []),
+ [{p, [E|P]} | otp_xmlify_blockquote(After)];
+otp_xmlify_blockquote([]) ->
+ [].
+
+%% otp_xmlify_code(E) -> Es
+%% Takes a <code> xmlElement and split it into a list of <code> and
+%% other xmlElements. Necessary when it contains more than a single
+%% xmlText element.
+%% Example:
+%% #xmlElement{name=code,
+%% content=[#xmlText{}, #xmlElement{name=br}, #xmlText{}]}
+%% =>
+%% [#xmlElement{name=code, content=[#xmlText{}]},
+%% #xmlElement{name=br},
+%% #xmlElement{name=code, content=[#xmlText{}]}]
+otp_xmlify_code(E) ->
+ otp_xmlify_code(E, E#xmlElement.content, []).
+otp_xmlify_code(Code, [#xmlText{} = E|Es], Acc) ->
+ otp_xmlify_code(Code, Es, [Code#xmlElement{content=[E]}|Acc]);
+otp_xmlify_code(Code, [#xmlElement{} = E|Es], Acc) ->
+ otp_xmlify_code(Code, Es, [E|Acc]);
+otp_xmlify_code(_Code, [], Acc) ->
+ lists:reverse(Acc).
+
+%% otp_xmlify_dl(Es1) -> Es2
+%% Insert empty <dd> elements if necessary.
+%% OTP DTDs does not allow <taglist>s with <tag>s but no <item>s.
+otp_xmlify_dl([#xmlElement{name=dt} = E|Es]) ->
+ [E|otp_xmlify_dl(Es, E)];
+otp_xmlify_dl([E|Es]) ->
+ [E|otp_xmlify_dl(Es)];
+otp_xmlify_dl([]) ->
+ [].
+
+otp_xmlify_dl([#xmlElement{name=dd} = E|Es], _DT) ->
+ [E|otp_xmlify_dl(Es)];
+otp_xmlify_dl([#xmlElement{name=dt} = E|Es], DT) ->
+ DD = DT#xmlElement{name=dd, attributes=[], content=[]},
+ [DD,E|otp_xmlify_dl(Es, E)];
+otp_xmlify_dl([E|Es], DT) ->
+ [E|otp_xmlify_dl(Es, DT)];
+otp_xmlify_dl([], DT) ->
+ DD = DT#xmlElement{name=dd, attributes=[], content=[]},
+ [DD].
+
+%% otp_xmlify_table(Es1) -> Es2
+%% Transform <table> contents into "text", that is, inline elements.
+otp_xmlify_table([#xmlText{} = E|Es]) ->
+ [E | otp_xmlify_table(Es)];
+otp_xmlify_table([#xmlElement{name=tbody} = E|Es]) ->
+ otp_xmlify_table(E#xmlElement.content)++otp_xmlify_table(Es);
+otp_xmlify_table([#xmlElement{name=tr} = E|Es]) ->
+ %% Insert newlines between table rows
+ otp_xmlify_table(E#xmlElement.content)++[{br,[]}]++otp_xmlify_table(Es);
+otp_xmlify_table([#xmlElement{name=th} = E|Es]) ->
+ [{em, E#xmlElement.content} | otp_xmlify_table(Es)];
+otp_xmlify_table([#xmlElement{name=td} = E|Es]) ->
+ otp_xmlify_e(E#xmlElement.content) ++ otp_xmlify_table(Es);
+otp_xmlify_table([]) ->
+ [].
+
+%%--Misc help functions used by otp_xmlify/1 et al---------------------
+
+%% find_next(Tag, Es) -> {Es1, Es2}
+%% Returns {Es1, Es2} where Es1 is the list of all elements up to (but
+%% not including) the first element with tag Tag in Es, and Es2
+%% is the remaining elements of Es.
+find_next(Tag, Es) ->
+ find_next(Tag, Es, []).
+find_next(Tag, [#xmlElement{name=Tag} = E | Es], AccEs) ->
+ {lists:reverse(AccEs), [E|Es]};
+find_next(Tag, [E|Es], AccEs) ->
+ find_next(Tag, Es, [E|AccEs]);
+find_next(_Tag, [], AccEs) ->
+ {lists:reverse(AccEs), []}.
+
+%% find_p_ending(Es, []) -> {Es1, Es2}
+%% Returns {Es1, Es2} where Es1 is the list of all elements up to (but
+%% not including) the first paragraph break in Es, and Es2 is
+%% the remaining elements of Es2.
+%% Paragraph break = <p> tag or empty line
+%% the next blank line, <p> or end-of-list as P, and the remaining
+%% elements of Es as After.
+find_p_ending([#xmlText{value="\n \n"++_} = E|Es], P) ->
+ {lists:reverse(P), [E|Es]};
+find_p_ending([#xmlElement{name=p} = E|Es], P) ->
+ {lists:reverse(P), [E|Es]};
+find_p_ending([E|Es], P) ->
+ find_p_ending(Es, [E|P]);
+find_p_ending([], P) ->
+ {lists:reverse(P), []}.
+
+%% is_paragraph(E | P) -> bool()
+%% P = {p, Es}
+is_paragraph(#xmlElement{name=p}) -> true;
+is_paragraph({p, _Es}) -> true;
+is_paragraph(_E) -> false.
+
+%% p_content(E | P) -> Es
+p_content(#xmlElement{content=Content}) -> Content;
+p_content({p, Content}) -> Content.
+
+%% is_empty(Str) -> bool()
+%% Str = string()
+%% Returns true if Str is empty in the sense that it contains nothing
+%% but spaces, tabs or newlines.
+is_empty("\n"++Str) ->
+ is_empty(Str);
+is_empty(" "++Str) ->
+ is_empty(Str);
+is_empty("\t"++Str) ->
+ is_empty(Str);
+is_empty("") ->
+ true;
+is_empty(_) ->
+ false.
+
+%% split(Str, Seps) -> [Str]
+split(Str, Seps) ->
+ split(Str, Seps, []).
+
+split([Ch|Str], Seps, Acc) ->
+ case lists:member(Ch, Seps) of
+ true -> split(Str, Seps, Acc);
+ false -> split(Str, Seps, Acc, [Ch])
+ end;
+split([], _Seps, Acc) ->
+ lists:reverse(Acc).
+
+split([Ch|Str], Seps, Acc, Chs) ->
+ case lists:member(Ch, Seps) of
+ true -> split(Str, Seps, [lists:reverse(Chs)|Acc]);
+ false -> split(Str, Seps, Acc, [Ch|Chs])
+ end;
+split([], _Seps, Acc, Chs) ->
+ lists:reverse([lists:reverse(Chs)|Acc]).
+
+%%--Functions for creating an erlref document---------------------------
+
+%% function_name(F) -> string()
+%% F = #xmlElement{name=function}
+%% Returns the name of a function as "name/arity".
+function_name(E) ->
+ get_attrval(name, E) ++ "/" ++ get_attrval(arity, E).
+
+%% functions(Fs) -> Es
+%% Fs = [{Name, F}]
+%% Name = string() "name/arity"
+%% F = #xmlElement{name=function}
+functions(Fs) ->
+ Es = lists:flatmap(fun ({Name, E}) -> function(Name, E) end, Fs),
+ if
+ Es==[] ->
+ [];
+ true ->
+ {funcs, Es}
+ end.
+
+function(_Name, E=#xmlElement{content = Es}) ->
+ TypeSpec = get_content(typespec, Es),
+ [?NL,{func, [ ?NL,
+ {name,
+ case funcheader(TypeSpec) of
+ [] ->
+ signature(get_content(args, Es),
+ get_attrval(name, E));
+ Spec -> Spec
+ end
+ },
+ ?NL,{fsummary, fsummary(Es)},
+ ?NL,local_types(TypeSpec),
+ ?NL,{desc,
+ label_anchor(E)++
+ deprecated(Es)++
+ fulldesc(Es)++
+ seealso_function(Es)}
+ ]}].
+
+fsummary([]) -> ["\s"];
+fsummary(Es) ->
+ Desc = get_content(description, Es),
+ case get_content(briefDescription, Desc) of
+ [] ->
+ fsummary_equiv(Es); % no description at all if no equiv
+ ShortDesc ->
+ text_only(ShortDesc)
+ end.
+
+fsummary_equiv(Es) ->
+ case get_content(equiv, Es) of
+ [] -> ["\s"];
+ Es1 ->
+ case get_content(expr, Es1) of
+ [] -> ["\s"];
+ [Expr] ->
+ ["Equivalent to ", Expr, ".",?NL]
+ end
+ end.
+
+label_anchor(E) ->
+ case get_attrval(label, E) of
+ "" -> [];
+ Ref -> [{marker, [{id, Ref}],[]},?NL]
+ end.
+
+label_anchor(Content, E) ->
+ case get_attrval(label, E) of
+ "" -> Content;
+ Ref -> {p,[{marker, [{id, Ref}],[]},
+ {em, Content}]}
+ end.
+
+signature(Es, Name) ->
+ [Name, "("] ++ seq(fun arg/1, Es) ++ [") -> term()", ?NL].
+
+arg(#xmlElement{content = Es}) ->
+ [get_text(argName, Es)].
+
+funcheader([]) -> [];
+funcheader(Es) ->
+ [t_name(get_elem(erlangName, Es))] ++ t_utype(get_elem(type, Es)).
+
+local_types([]) -> [];
+local_types(Es) ->
+ local_defs2(get_elem(localdef, Es)).
+
+local_defs2([]) -> [];
+local_defs2(Es) ->
+ {type,[?NL | [{v, localdef2(E)} || E <- Es]]}.
+
+%% Like localdef/1, but does not use label_anchor/2 -- we don't want any
+%% markers or em tags in <v> tag, plain text only!
+localdef2(#xmlElement{content = Es}) ->
+ case get_elem(typevar, Es) of
+ [] ->
+ t_utype(get_elem(type, Es));
+ [V] ->
+ t_var(V) ++ [" = "] ++ t_utype(get_elem(type, Es))
+ end.
+
+type_name(#xmlElement{content = Es}) ->
+ t_name(get_elem(erlangName, get_content(typedef, Es))).
+
+types(Ts) ->
+ Es = lists:flatmap(fun ({Name, E}) -> typedecl(Name, E) end, Ts),
+ [?NL, {taglist,[?NL|Es]}].
+
+typedecl(Name, #xmlElement{content = Es}) ->
+ TypedefEs = get_content(typedef, Es),
+ Id = "type-"++Name,
+ [{tag, typedef(TypedefEs)},
+ ?NL,
+ {item, [{marker,[{id,Id}],[]} |
+ local_defs(get_elem(localdef, TypedefEs)) ++ fulldesc(Es)]},
+ ?NL].
+
+typedef(Es) ->
+ Name = ([t_name(get_elem(erlangName, Es)), "("]
+ ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])),
+ case get_elem(type, Es) of
+ [] ->
+ [{tt, Name}];
+ Type ->
+ [{tt, Name ++ [" = "] ++ t_utype(Type)}]
+ end.
+
+local_defs([]) -> [];
+local_defs(Es) ->
+ [?NL, {ul, [{li, [{tt, localdef(E)}]} || E <- Es]}].
+
+localdef(E = #xmlElement{content = Es}) ->
+ Var = case get_elem(typevar, Es) of
+ [] ->
+ [label_anchor(t_abstype(get_content(abstype, Es)), E)];
+ [V] ->
+ t_var(V)
+ end,
+ Var ++ [" = "] ++ t_utype(get_elem(type, Es)).
+
+deprecated(Es) ->
+ case get_content(deprecated, Es) of
+ [] -> [];
+ DeprEs ->
+ Es2 = get_content(fullDescription,
+ get_content(description, DeprEs)),
+ Es3 = otp_xmlify_e(Es2),
+ [{p, [{em, ["This function is deprecated: "]} |Es3]}, ?NL]
+ end.
+
+fulldesc(Es) ->
+ case get_content(fullDescription, get_content(description, Es)) of
+ [] ->
+ index_desc(Es);
+ Desc ->
+ [?NL|otp_xmlify(Desc)] ++ [?NL]
+ end.
+
+index_desc(Es) ->
+ Desc = get_content(description, Es),
+ case get_content(briefDescription, Desc) of
+ [] ->
+ equiv(Es); % no description at all if no equiv
+ ShortDesc ->
+ ShortDesc
+ end.
+
+seealso_module(Es) ->
+ case get_elem(see, Es) of
+ [] -> [];
+ Es1 ->
+ {section,[{title,["See also"]},{p,seq(fun see/1, Es1, [])}]}
+ end.
+seealso_function(Es) ->
+ case get_elem(see, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{em, ["See also:"]}, " "] ++ seq(fun see/1, Es1, ["."])},
+ ?NL]
+ end.
+
+%% ELEMENT see PCDATA
+%% ATTLIST name PCDATA
+%% href PCDATA
+see(#xmlElement{content=Es0} = E) ->
+ Href0 = get_attrval(href, E),
+ {Href, Es} = otp_xmlify_a_href(Href0, Es0),
+ [{seealso, [{marker, Href}], Es}].
+
+equiv(Es) ->
+ case get_content(equiv, Es) of
+ [] -> ["\s"];
+ Es1 ->
+ case get_content(expr, Es1) of
+ [] -> [];
+ [Expr] ->
+ Expr1 = [Expr],
+ Expr2 = case get_elem(see, Es1) of
+ [] ->
+ {c,Expr1};
+ [E=#xmlElement{}] ->
+ case get_attrval(href, E) of
+ "" ->
+ {c,Expr1};
+ Ref ->
+ {seealso, [{marker, Ref}], Expr1}
+ end
+ end,
+ [{p, ["Equivalent to ", Expr2, "."]}, ?NL]
+ end
+ end.
+
+authors(Es) ->
+ case get_elem(author, Es) of
+ [] ->
+ [?NL,{aname,["\s"]},?NL,{email,["\s"]}];
+ Es1 ->
+ [?NL|seq(fun author/1, Es1, "", [])]
+ end.
+
+author(E=#xmlElement{}) ->
+ Name = case get_attrval(name, E) of
+ [] -> "\s";
+ N -> N
+ end,
+ Mail = case get_attrval(email, E) of
+ [] -> "\s";
+ M -> M
+ end,
+ [?NL,{aname,[Name]},?NL,{email,[Mail]}].
+
+t_name([E]) ->
+ N = get_attrval(name, E),
+ case get_attrval(module, E) of
+ "" -> N;
+ M ->
+ S = M ++ ":" ++ N,
+ case get_attrval(app, E) of
+ "" -> S;
+ A -> "//" ++ A ++ "/" ++ S
+ end
+ end.
+
+t_utype([E]) ->
+ t_utype_elem(E).
+
+t_utype_elem(E=#xmlElement{content = Es}) ->
+ case get_attrval(name, E) of
+ "" -> t_type(Es);
+ Name ->
+ T = t_type(Es),
+ case T of
+ [Name] -> T; % avoid generating "Foo::Foo"
+ T -> [Name] ++ ["::"] ++ T
+ end
+ end.
+
+t_type([E=#xmlElement{name = typevar}]) ->
+ t_var(E);
+t_type([E=#xmlElement{name = atom}]) ->
+ t_atom(E);
+t_type([E=#xmlElement{name = integer}]) ->
+ t_integer(E);
+t_type([E=#xmlElement{name = float}]) ->
+ t_float(E);
+t_type([#xmlElement{name = nil}]) ->
+ t_nil();
+t_type([#xmlElement{name = list, content = Es}]) ->
+ t_list(Es);
+t_type([#xmlElement{name = tuple, content = Es}]) ->
+ t_tuple(Es);
+t_type([#xmlElement{name = 'fun', content = Es}]) ->
+ t_fun(Es);
+t_type([#xmlElement{name = abstype, content = Es}]) ->
+ t_abstype(Es);
+t_type([#xmlElement{name = union, content = Es}]) ->
+ t_union(Es);
+t_type([#xmlElement{name = record, content = Es}]) ->
+ t_record(Es).
+
+t_var(E) ->
+ [get_attrval(name, E)].
+
+t_atom(E) ->
+ [get_attrval(value, E)].
+
+t_integer(E) ->
+ [get_attrval(value, E)].
+
+t_float(E) ->
+ [get_attrval(value, E)].
+
+t_nil() ->
+ ["[]"].
+
+t_list(Es) ->
+ ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"].
+
+t_tuple(Es) ->
+ ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]).
+
+t_fun(Es) ->
+ ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
+ [") -> "] ++ t_utype(get_elem(type, Es))).
+
+t_record([E|Es]) ->
+ ["#", get_attrval(value, E), "{"++ seq(fun t_field/1, Es) ++"}"].
+t_field(#xmlElement{name=field, content=[Atom,Type]}) ->
+ [get_attrval(value, Atom), "="] ++ t_utype_elem(Type).
+
+t_abstype(Es) ->
+ case split_at_colon(t_name(get_elem(erlangName, Es)),[]) of
+ {Mod,Type} ->
+ [Type, "("] ++
+ seq(fun t_utype_elem/1, get_elem(type, Es), [")"]) ++
+ [" (see module ", Mod, ")"];
+ Type ->
+ [Type, "("] ++
+ seq(fun t_utype_elem/1, get_elem(type, Es), [")"])
+ end.
+
+%% Split at one colon, but not at two (or more)
+split_at_colon([$:,$:|_]=Rest,Acc) ->
+ lists:reverse(Acc)++Rest;
+split_at_colon([$:|Type],Acc) ->
+ {lists:reverse(Acc),Type};
+split_at_colon([Char|Rest],Acc) ->
+ split_at_colon(Rest,[Char|Acc]);
+split_at_colon([],Acc) ->
+ lists:reverse(Acc).
+
+t_union(Es) ->
+ seq(fun t_utype_elem/1, Es, " | ", []).
+
+%% seq(Fun, Es)
+%% seq(Fun, Es, Tail)
+%% seq(Fun, Es, Sep, Tail) -> [string()]
+%% Fun = function(E) -> [string()]
+%% Sep = string()
+%% Tail = [string()]
+%% Applies Fun to each element E in Es and return the appended list of
+%% strings, separated by Sep which defaults to ", " and ended by Tail
+%% which defaults to [].
+seq(Fun, Es) ->
+ seq(Fun, Es, []).
+seq(Fun, Es, Tail) ->
+ seq(Fun, Es, ", ", Tail).
+seq(Fun, [E], _Sep, Tail) ->
+ Fun(E) ++ Tail;
+seq(Fun, [E | Es], Sep, Tail) ->
+ Fun(E) ++ [Sep] ++ seq(Fun, Es, Sep, Tail);
+seq(_Fun, [], _Sep, Tail) ->
+ Tail.
+
+%%--Misc functions for accessing fields etc-----------------------------
+
+%% Type definitions used below:
+%% E = #xmlElement{} | #xmlText{}
+%% Es = [E]
+%% Tag = atom(), XHTML tag
+%% Name = atom(), XHTML attribute name
+%% Attrs = [#xmlAttribute{}]
+%% Ts = [#xmlText{}]
+
+%% parent(E) -> module | overview
+parent(E) ->
+ Parents = E#xmlElement.parents,
+ {Parent,_} = lists:last(Parents),
+ Parent.
+
+%% get_elem(Tag, Es1) -> Es2
+%% Returns a list of all elements in Es which have the name Tag.
+get_elem(Name, [#xmlElement{name = Name} = E | Es]) ->
+ [E | get_elem(Name, Es)];
+get_elem(Name, [_ | Es]) ->
+ get_elem(Name, Es);
+get_elem(_, []) ->
+ [].
+
+%% get_attr(Name, Attrs1) -> Attrs2
+%% Returns a list of all attributes in Attrs1 which have the name Name.
+get_attr(Name, [#xmlAttribute{name = Name} = A | As]) ->
+ [A | get_attr(Name, As)];
+get_attr(Name, [_ | As]) ->
+ get_attr(Name, As);
+get_attr(_, []) ->
+ [].
+
+%% get_attrval(Name, E) -> string()
+%% If E has one attribute with name Name, return its value, otherwise ""
+get_attrval(Name, #xmlElement{attributes = As}) ->
+ case get_attr(Name, As) of
+ [#xmlAttribute{value = V}] ->
+ V;
+ [] -> ""
+ end.
+
+%% get_content(Tag, Es1) -> Es2
+%% If there is one element in Es1 with name Tag, returns its contents,
+%% otherwise []
+get_content(Name, Es) ->
+ case get_elem(Name, Es) of
+ [#xmlElement{content = Es1}] ->
+ Es1;
+ [] -> []
+ end.
+
+%% get_text(Tag, Es) -> string()
+%% If there is one element in Es with name Tag, and its content is
+%% a single xmlText, return the value of this xmlText.
+%% Otherwise return "".
+get_text(Name, Es) ->
+ case get_content(Name, Es) of
+ [#xmlText{value = Text}] ->
+ Text;
+ [] -> ""
+ end.
+
+%% get_text(E) -> string()
+%% Return the value of an single xmlText which is the content of E,
+%% possibly recursively.
+get_text(#xmlElement{content=[#xmlText{value=Text}]}) ->
+ Text;
+get_text(#xmlElement{content=[E]}) ->
+ get_text(E).
+
+%% text_only(Es) -> Ts
+%% Takes a list of xmlElement and xmlText and return a lists of xmlText.
+text_only([#xmlElement{} = E |Es]) ->
+ text_only(E#xmlElement.content) ++ text_only(Es);
+text_only([#xmlText{} = E |Es]) ->
+ [E | text_only(Es)];
+text_only([]) ->
+ [].
diff --git a/lib/docbuilder/src/docb_gen.erl b/lib/docbuilder/src/docb_gen.erl
new file mode 100644
index 0000000000..0d8d640324
--- /dev/null
+++ b/lib/docbuilder/src/docb_gen.erl
@@ -0,0 +1,138 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_gen).
+
+-export([module/1, module/2, users_guide/1, users_guide/2]).
+
+-record(args, {suffix=".xml",
+ layout=docb_edoc_xml_cb,
+ def=[],
+ includes=[],
+ preprocess=false,
+ sort_functions=true}).
+
+%% module(File) -> ok | {error, Reason}
+%% module(File, Opts) -> ok | {error, Reason}
+%% File = string(), file name with or without ".erl" extension
+%% Opts -- see code
+%% Reason = badfile | {badopt, Term}
+module(File0) ->
+ module(File0, []).
+module(File0, RawOpts) ->
+ File = case filename:extension(File0) of
+ ".erl" -> File0;
+ _ -> File0++".erl"
+ end,
+ case filelib:is_regular(File) of
+ true ->
+ case parse(RawOpts, #args{}) of
+ {ok, Args} ->
+ Opts = [{def, Args#args.def},
+ {includes, Args#args.includes},
+ {preprocess, Args#args.preprocess},
+ {sort_functions, Args#args.sort_functions},
+
+ {app_default, "OTPROOT"},
+ {file_suffix, Args#args.suffix},
+ {dir, "."},
+ {layout, Args#args.layout}],
+ edoc:file(File, Opts);
+ Error ->
+ Error
+ end;
+ false ->
+ {error, badfile}
+ end.
+
+%% users_guide(File) -> ok | {error, Reason}
+%% users_guide(File, Opts) -> ok | {error, Reason}
+%% File = string()
+%% Opts -- see code
+%% Reason = badfile | {badopt, Opt}
+users_guide(File) ->
+ users_guide(File, []).
+users_guide(File, RawOpts) ->
+ case filelib:is_regular(File) of
+ true ->
+ case parse(RawOpts, #args{}) of
+ {ok, Args} ->
+ Opts = [{def, Args#args.def},
+ {app_default, "OTPROOT"},
+ {file_suffix, Args#args.suffix},
+ {layout, Args#args.layout}],
+
+ Env = edoc_lib:get_doc_env(Opts),
+
+ {ok, Tags} =
+ edoc_extract:file(File, overview, Env, Opts),
+ Data =
+ edoc_data:overview("Overview", Tags, Env, Opts),
+ F = fun(M) -> M:overview(Data, Opts) end,
+ Text = edoc_lib:run_layout(F, Opts),
+
+ OutFile = "chapter" ++ Args#args.suffix,
+ edoc_lib:write_file(Text, ".", OutFile);
+ Error ->
+ Error
+ end;
+ false ->
+ {error, badfile}
+ end.
+
+parse([{output,xml} | RawOpts], Args) ->
+ parse(RawOpts, Args); % default, no update of record necessary
+parse([{output,sgml} | RawOpts], Args) ->
+ parse(RawOpts, Args#args{suffix=".sgml", layout=docb_edoc_sgml_cb});
+parse([{def,Defs} | RawOpts], Args) ->
+ case parse_defs(Defs) of
+ true ->
+ Args2 = Args#args{def=Args#args.def++Defs},
+ parse(RawOpts, Args2);
+ false ->
+ {error, {badopt, {def,Defs}}}
+ end;
+parse([{includes,Dirs} | RawOpts], Args) ->
+ case parse_includes(Dirs) of
+ true ->
+ Args2 = Args#args{includes=Args#args.includes++Dirs},
+ parse(RawOpts, Args2);
+ false ->
+ {error, {badopt, {includes,Dirs}}}
+ end;
+parse([{preprocess,Bool} | RawOpts], Args) when Bool==true;
+ Bool==false ->
+ parse(RawOpts, Args#args{preprocess=Bool});
+parse([{sort_functions,Bool} | RawOpts], Args) when Bool==true;
+ Bool==false ->
+ parse(RawOpts, Args#args{sort_functions=Bool});
+parse([], Args) ->
+ {ok, Args};
+parse([Opt | _RawOpts], _Args) ->
+ {error, {badopt, Opt}}.
+
+parse_defs(Defs) ->
+ lists:all(fun({Key,Val}) when is_atom(Key), is_list(Val) -> true;
+ (_) -> false
+ end,
+ Defs).
+
+parse_includes(Dirs) ->
+ lists:all(fun(Dir) when is_list(Dir) -> true;
+ (_) -> false
+ end,
+ Dirs).
diff --git a/lib/docbuilder/src/docb_html.erl b/lib/docbuilder/src/docb_html.erl
new file mode 100644
index 0000000000..9aea4c8a66
--- /dev/null
+++ b/lib/docbuilder/src/docb_html.erl
@@ -0,0 +1,394 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_html).
+
+-export([rule/2, rule/3]).
+
+rule([p, item, list|_], {_, _, _}) ->
+ {"", "<br />\n"};
+rule([p, item, taglist|_], {_, _, _}) ->
+ {"", "<br />\n"};
+rule([p|_], _) ->
+ {"\n<p>", "\n</p>"};
+
+rule([pre|_], _) ->
+ {"\n<div class=\"example\"><pre>\n", "\n</pre></div>\n"};
+
+rule([input|_], _) ->
+ {"<strong>", "</strong>"};
+
+rule([quote|_], _) ->
+ {"\n<blockquote>\n", "\n</blockquote>\n"};
+
+rule([i|_], _) ->
+ {"<em>", "</em>"};
+
+rule([b|_], _) ->
+ {"<strong>", "</strong>"};
+
+rule([c|_], _) ->
+ {"<span class=\"code\">", "</span>"};
+
+rule([em|_], _) ->
+ {"<strong>", "</strong>"};
+
+rule([sub|_], _) ->
+ {"<sub>", "</sub>"};
+
+rule([sup|_], _) ->
+ {"<sup>", "</sup>"};
+
+rule([termdef|_], _) ->
+ {drop, ""};
+
+rule([citedef|_], _) ->
+ {drop, ""};
+
+rule([br|_], _) ->
+ {"<br />\n", ""};
+
+rule([digression|_], _) ->
+ {"<table>\n"
+ " <tr>\n"
+ " <td width=\"23\"></td>\n"
+ " <td>\n"
+ " <font size=\"-1\">\n",
+ " </font>\n"
+ " </td>\n"
+ " </tr>\n"
+ "</table>\n"};
+
+rule([list, item, list|_], {_, ["ORDERED"], _}) ->
+ {"\n<ol>\n", "\n</ol>\n"};
+rule([list, item, taglist|_], {_, ["ORDERED"], _}) ->
+ {"\n<ol>\n", "\n</ol>\n"};
+rule([list|_], {_, ["ORDERED"], _}) ->
+ {"\n<ol>\n", "\n</ol>\n"};
+rule([list, item, list|_], {_, ["BULLETED"], _}) ->
+ {"\n<ul>\n", "\n</ul>\n"};
+rule([list, item, taglist|_], {_, ["BULLETED"], _}) ->
+ {"\n<ul>\n", "\n</ul>\n"};
+rule([list|_], {_, ["BULLETED"], _}) ->
+ {"\n<ul>\n", "\n</ul>\n"};
+
+rule([taglist, item, taglist|_], _) ->
+ {"\n<dl>\n", "\n</dl>\n"};
+rule([taglist, item, list|_], _) ->
+ {"\n<dl>\n", "\n</dl>\n"};
+rule([taglist|_], _) ->
+ {"\n<dl>\n", "\n</dl>\n"};
+
+rule([tag|_], _) ->
+ {"\n<dt>\n", "\n</dt>\n"};
+
+rule([item, list|_], _) ->
+ {"\n<li>\n", "\n</li>\n\n"};
+rule([item, taglist|_], _) ->
+ {"\n<dd>\n", "\n</dd>\n"};
+
+rule([image|_], {_, [File], _}) ->
+ File2 =
+ case filename:extension(File) of
+ [] -> File ++ ".gif";
+ _ -> File
+ end,
+ {["\n<center>\n", "<img alt=\"", File2, "\" src=\"", File2,
+ "\"/><br/>\n"],
+ "\n</center>\n"};
+
+rule([icaption|_], _) ->
+ {"<em>", "</em>\n"};
+
+rule([url|_], {_, [HREF], _}) ->
+ URI = docb_html_util:make_uri(HREF),
+ {io_lib:format("<a target=\"_top\" href=\"~s\">", [URI]), "</a>"};
+
+rule([marker|_], {_, [ID], _}) ->
+ %% remove all chars before first # including the #
+ {ok, NewID, _} = regexp:sub(ID, "^[^#]*#", ""),
+ %% replace "/" with "-" because "/" xhtml does not
+ %% allow "/" in the name attribute of element <a>
+ %% so we have to do the same as for marker i.e
+ %% Function/Arity is translated to an anchor in xhtml
+ %% like this : <a name="Function-Arity"/>
+ NewID2 = [case X of $/ -> $-;_->X end||X <- NewID],
+ {drop, ["<a name=\"", NewID2, "\"><!-- Empty --></a>"]};
+
+rule([table|_], {_, ["", ""], Ts}) ->
+ {newargs,
+ "\n<center>\n"
+ "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
+ reorder_table(Ts),
+ "\n</table>\n"
+ "</center>\n"};
+rule([table|_], {_, [Width, ""], Ts}) ->
+ {newargs,
+ ["\n<center>\n"
+ "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\" ",
+ "width=\"", Width, "%\">\n"],
+ reorder_table(Ts),
+ "\n</table>\n"
+ "</center>\n"};
+
+%% The clauses above are for the report DTD. This one is for the other
+%% DTDs.
+rule([table|_], {_, ["LEFT"], Ts}) ->
+ {newargs,
+ "\n"
+ "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
+ reorder_table(Ts),
+ "\n</table>\n"};
+
+rule([table|_], {_, _, Ts}) ->
+ {newargs,
+ "\n<center>\n"
+ "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
+ reorder_table(Ts),
+ "\n</table>\n"
+ "</center>\n"};
+
+rule([row|_], _) ->
+ {" <tr>\n", "\n </tr>\n"};
+
+rule([cell|_], {_, ["", ""], _}) ->
+ {" <td>\n", "\n </td>\n"};
+rule([cell|_], {_, [Align, ""], _}) ->
+ {[" <td align=\"", string:to_lower(Align), "\">\n"], "\n </td>\n"};
+rule([cell|_], {_, ["", VAlign], _}) ->
+ {[" <td valign=\"", string:to_lower(VAlign), "\">\n"], "\n </td>\n"};
+rule([cell|_], {_, [Align, VAlign], _}) ->
+ {[" <td align=\"", string:to_lower(Align), "\" valign=\"", string:to_lower(VAlign), "\">\n"],
+ "\n </td>\n"};
+
+rule([tcaption|_], _) ->
+ {" <caption align=\"bottom\"><em>", "</em></caption>\n"};
+
+rule([codeinclude|_], {_, [File, Tag, _Type], _}) ->
+%% Type can be "ERL", "C" or "NONE"
+ {ok,Data} = docb_html_util:code_include(File, Tag),
+ {drop, ["\n<div class=\"example\"><pre>\n", Data,
+ "\n</pre></div>\n"]};
+
+rule([erleval|_], {_, [Expr], _}) ->
+ docb_html_util:erl_eval(Expr);
+
+rule([pcdata, pre|_], {_, _, Data}) ->
+ %% Do not remove leading spaces.
+ {drop, docb_html_util:pcdata_to_html(Data, false)};
+
+rule([pcdata|_], {_, _, Data}) ->
+ {drop, docb_html_util:pcdata_to_html(Data)}.
+
+rule([seealso|_], {_, [Marker], _}, Opts) ->
+ Href =
+ case docb_util:html_snippet(seealso, Marker, Opts) of
+ "" ->
+ %% DocBuilder default behavior:
+ %% Marker is of format "Path#Fragment", both optional.
+ %% Translated to <A HREF="Path.html#Fragment">
+ case string:chr(Marker, $#) of
+ 0 -> % No Fragment
+ Marker++".html";
+ 1 -> % No Path
+ %% replace "/" with "-" because "/" xhtml does not
+ %% allow "/" in the name attribute of element <a>
+ %% so we have to do the same as for marker i.e
+ %% Function/Arity is translated to an anchor in xhtml
+ %% like this : <a name="Function-Arity"/>
+ [case X of $/ -> $-;_->X end||X <- Marker];
+ _ ->
+ Marker1 = [case X of $/ -> $-;_->X end||X <- Marker],
+ case string:tokens(Marker1, "#") of
+ [Path] -> % # at end, remove it
+ Path++".html";
+ [Path | Frag0] ->
+ Path++".html#"++
+ docb_util:join(Frag0, "#")
+ end
+ end;
+ Href0 ->
+ %% User defined behavior, use result as-is
+ Href0
+ end,
+ {{["<a href=\"", Href, "\">"], "</a>"}, Opts};
+
+rule([warning|_], _, Opts) ->
+ docb_html_util:copy_pics("warning.gif", "warning.gif", Opts),
+ {{"\n<div class=\"warning\">\n"
+ "<div class=\"label\">Warning</div>\n"
+ "<div class=\"content\">\n",
+ "\n</div>"
+ "\n</div>\n"}, Opts};
+
+rule([note|_], _, Opts) ->
+ docb_html_util:copy_pics("note.gif", "note.gif", Opts),
+ {{"\n<div class=\"note\">\n"
+ "<div class=\"label\">Note</div>\n"
+ "<div class=\"content\">",
+ "\n</div>"
+ "\n</div>\n"}, Opts};
+
+rule([path|_], {_, [UNIX, Windows], [{pcdata, _, Text}]}, Opts) ->
+ UnixPart =
+ docb_util:an_option({ptype,"unix"}, Opts) and (UNIX/=""),
+ WinPart =
+ docb_util:an_option({ptype,"windows"}, Opts) and (Windows/=""),
+ if
+ UnixPart, WinPart ->
+ {{drop, [docb_html_util:pcdata_to_html(Text),
+ " <font size=\"-2\">(<code>UNIX: ",
+ docb_html_util:attribute_cdata_to_html(UNIX),
+ ", ",
+ "Windows: ",
+ docb_html_util:attribute_cdata_to_html(Windows),
+ "</code>)</font>"]},
+ Opts};
+ UnixPart ->
+ {{drop, [docb_html_util:pcdata_to_html(Text),
+ " <font size=\"-1\">(<code>UNIX: ",
+ docb_html_util:attribute_cdata_to_html(UNIX),
+ "</code>)</font>"]},
+ Opts};
+ WinPart ->
+ {{drop, [docb_html_util:pcdata_to_html(Text),
+ " <font size=\"-1\">(<code>Windows: ",
+ docb_html_util:attribute_cdata_to_html(Windows),
+ "</code>)</font>"]},
+ Opts};
+ true ->
+ {{drop, docb_html_util:pcdata_to_html(Text)}, Opts}
+ end;
+
+rule([term|_], {_, [ID], _}, Opts) ->
+ case docb_util:an_option(dict, Opts) of
+ false ->
+ case docb_util:lookup_option({defs, term}, Opts) of
+ false ->
+ {{drop, ["<em><strong>",
+ ID,
+ "</strong></em> "]}, Opts};
+ TermList ->
+ case lists:keysearch(ID, 1, TermList) of
+ false ->
+ {{drop, ["<em><strong>", ID,
+ "</strong></em> "]},
+ Opts};
+ {value, {ID, Name, _Description, _Resp}} ->
+ {{drop, ["<em><strong>", Name,
+ "</strong></em> "]},
+ Opts};
+ {value, {ID, Name, _Description}} ->
+ {{drop, [ "<em><strong>", Name,
+ "</strong></em> "]},
+ Opts}
+ end
+ end;
+ true ->
+ case docb_util:lookup_option({defs, term}, Opts) of
+ false ->
+ {{drop, ["<em><strong>", ID,
+ "</strong></em> "]}, Opts};
+ TermList ->
+ PartApplication =
+ docb_util:lookup_option(part_application, Opts),
+ case lists:keysearch(ID, 1, TermList) of
+ false ->
+ {{drop, ["<a href=\"", PartApplication,
+ "_term.html#", ID, "\">", ID,
+ "</a> "]}, Opts};
+ {value, {ID, Name, _Description, _Resp}} ->
+ {{drop, ["<a href=\"", PartApplication,
+ "_term.html#", ID, "\">", Name,
+ "</a> "]}, Opts};
+ {value, {ID, Name, _Description}} ->
+ {{drop, ["<a href=\"", PartApplication,
+ "_term.html#", ID, "\">", Name,
+ "</a> "]}, Opts}
+ end
+ end
+ end;
+
+rule([cite|_], {_, [ID], _}, Opts) ->
+ case docb_util:an_option(dict, Opts) of
+ false ->
+ case docb_util:lookup_option({defs, cite}, Opts) of
+ false ->
+ {{drop, ["<em><strong>", ID, "</strong></em> "]},
+ Opts};
+ CiteList ->
+ case lists:keysearch(ID, 1, CiteList) of
+ false ->
+ {{drop,
+ ["<em><strong>", ID, "</strong></em> "]},
+ Opts};
+
+ {value, {ID, Name, _Description, _Resp}} ->
+ {{drop, ["<em><strong>", Name,
+ "</strong></em> "]},
+ Opts};
+ {value, {ID, Name, _Description}} ->
+ {{drop, ["<em><strong>", Name,
+ "</strong></em> "]},
+ Opts}
+ end
+ end;
+ true ->
+ case docb_util:lookup_option({defs, cite}, Opts) of
+ false ->
+ {{drop, ["<em><strong>", ID, "</strong></em> "]},
+ Opts};
+ CiteList ->
+ PartApp =
+ docb_util:lookup_option(part_application, Opts),
+ case lists:keysearch(ID, 1, CiteList) of
+ false ->
+ {{drop, ["<a href=\"", PartApp,
+ "_cite.html#", ID, "\">", ID,
+ "</a> "]},
+ Opts};
+ {value, {ID, Name, _Description, _Resp}} ->
+ {{drop, ["<a href=\"", PartApp,
+ "_cite.html#", ID, "\">", Name,
+ "</a> "]},
+ Opts};
+ {value, {ID, Name, _Description}} ->
+ {{drop, ["<a href=\"", PartApp,
+ "_cite.html#", ID, "\">", Name,
+ "</a> "]},
+ Opts}
+ end
+ end
+ end;
+
+rule([code|_], {_, [Type], [{pcdata, _, Code}]}, Opts) ->
+ case lists:member(Type,["ERL","C","NONE"]) of
+ true ->
+ {{drop, ["\n<div class=\"example\"><pre>\n", docb_html_util:element_cdata_to_html(Code),
+ "\n</pre></div>\n"]}, Opts};
+ false ->
+ exit({error,"unknown type of <code>"})
+ end.
+
+reorder_table(TableContent) ->
+ reorder_table(TableContent, [], []).
+reorder_table([], Caption, NewTableContent) ->
+ Caption ++ lists:reverse(NewTableContent);
+reorder_table([{tcaption,_,_} = Caption | TableContent], _, NewTableContent) ->
+ reorder_table(TableContent, [Caption], NewTableContent);
+reorder_table([Row | TableContent], Caption, NewTableContent) ->
+ reorder_table(TableContent, Caption, [Row | NewTableContent]).
diff --git a/lib/docbuilder/src/docb_html_layout.erl b/lib/docbuilder/src/docb_html_layout.erl
new file mode 100644
index 0000000000..dca80ac58e
--- /dev/null
+++ b/lib/docbuilder/src/docb_html_layout.erl
@@ -0,0 +1,380 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_html_layout).
+
+-export([report_top/2, report_bot/1,
+ first_top/2, first_bot/1,
+ ref_top/2, ref_bot/1,
+ chapter_top/2, chapter_bot/1,
+ application_toc_top/3, application_toc_top/4,
+ part_toc_top/3, part_toc_top/4, part_toc_bot/0,
+ index_top/1, index_bot/0]).
+
+%% Report
+
+report_top(Data, Opts) ->
+ [Title, Prepared, _Responsible, DocNo, _Approved, _Checked, _Date,
+ Vsn0, _File] = Data,
+ html_header(Title, Opts) ++
+ docb_util:html_snippet(top, Opts) ++
+"<center>
+<h1>" ++ Title ++ "</h1>
+<big>
+ " ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
+ " ++ Prepared ++ "<br />
+</big>
+</center>
+".
+
+report_bot(Opts) ->
+ docb_util:html_snippet(bottom, Opts) ++
+"</body>
+</html>
+".
+
+%% First
+
+first_top(Data, Opts) ->
+ [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked, _Date,
+ Vsn0, _File] = Data,
+ html_header(Title, Opts) ++
+ docb_util:html_snippet(top, Opts) ++
+"<center>
+<h1>" ++ Title ++ "</h1>
+<big>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
+</big>
+</center>
+".
+
+first_bot(Opts) ->
+ report_bot(Opts).
+
+%% Reference
+
+ref_top(Data, Opts) ->
+ [Title, _Prepared, _Responsible, _DocNo, _Approved, _Checked,
+ _Date, _Rev, _File] = Data,
+ ref_html_header(Title, Opts) ++
+"<!-- refpage -->\n" ++
+ docb_util:html_snippet(top, Opts) ++
+"<center>
+<h1>" ++ Title ++ "</h1>
+</center>".
+
+ref_bot(Opts) ->
+ docb_util:html_snippet(bottom, Opts) ++
+"</body>
+</html>
+".
+
+%% Chapter
+
+chapter_top(Data, Opts) ->
+ [Title, _Prepared, _Responsible, _DocNo, _Approved, _Checked,
+ _Date, _Rev, _File] = Data,
+ html_header(Title, Opts) ++
+ docb_util:html_snippet(top, Opts).
+
+chapter_bot(Opts) ->
+ report_bot(Opts).
+
+%% Application ToC
+
+application_toc_top(Data, DocName, Opts) ->
+ [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
+ _Date, Vsn0, _File] = Data,
+ html_header(Title, []) ++
+"<center>
+<strong>" ++ Title ++ "</strong>
+<p>
+<small>
+ " ++ DocNo ++ version(Opts, Vsn0) ++ "
+</small>
+</p>
+<p>
+<small>
+ <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_index.html\">Index</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>" ++ top_index(Opts) ++
+"</small>
+</p>
+</center>
+<p>
+<small>
+<strong>Table of Contents</strong>
+</small>
+</p>
+".
+
+application_toc_top(Data, DocName, Opts, HRefTexts) ->
+ [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
+ _Date, Vsn0, _File] = Data,
+ html_header(Title, []) ++
+"<center>
+<small>
+" ++
+ docb_util:join(
+ lists:map(
+ fun({HRef, Text}) ->
+ "<a target=\"_top\" href=\"" ++ HRef ++ "\">" ++
+ Text ++ "</a>"
+ end,
+ HRefTexts), " | ") ++ top_index(Opts) ++
+"</small>
+<p>
+<strong>" ++ Title ++ "</strong>
+</p>
+<p>
+<small>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
+</small>
+</p>
+<p>
+<small>
+ <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_index.html\">Index</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>
+</small>
+</p>
+</center>
+<p>
+<small>
+<strong>Table of Contents</strong>
+</small>
+</p>
+".
+
+%% Part ToC
+
+part_toc_top(Data, DocName, Opts) ->
+ [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
+ _Date, Vsn0, _File] = Data,
+ html_header(Title, []) ++
+"<center>
+<p>
+<strong>" ++ Title ++ "</strong>
+</p>
+<p>
+<small>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
+</small>
+</p>
+<p>
+<small>
+ <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>" ++
+ top_index(Opts) ++
+"</small>
+</p>
+</center>
+<p>
+<small>
+<strong>Table of Contents</strong>
+</small>
+</p>
+".
+
+part_toc_top(Data, DocName, Opts, HRefTexts) ->
+ [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
+ _Date, Vsn0, _File] = Data,
+ html_header(Title, []) ++
+"<center>
+<p>
+<small>
+" ++
+ docb_util:join(
+ lists:map(
+ fun({HRef, Text}) ->
+ "<a target=\"_top\" href=\"" ++ HRef ++ "\">" ++
+ Text ++ "</a>"
+ end,
+ HRefTexts), " | ") ++ top_index(Opts) ++
+"</small>
+</p>
+<p>
+<strong>" ++ Title ++ "</strong>
+</p>
+<p>
+<small>
+ " ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
+</small>
+</p>
+<p>
+<small>
+ <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
+ <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>
+</small>
+</p>
+</center>
+<p>
+<small>
+<strong>Table of Contents</strong>
+</small>
+</p>
+".
+
+part_toc_bot() ->
+"</body >
+</html>
+".
+
+%% Index
+
+index_top(_Data) ->
+ ref_html_header("INDEX", []) ++
+"<h1>INDEX</h1>
+<p><em>Emphasized</em> index entries refer to <em>modules</em>
+and <code>Courier</code> ditos to <code>functions</code>.\n</p>\n".
+
+index_bot() ->
+ part_toc_bot().
+
+%% Internal functions
+
+html_header(Title, Opts) ->
+ Vsn = docb_util:version(),
+%%"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
+"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<!-- This document was generated using DocBuilder-" ++ Vsn ++ " -->
+<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
+<head>
+ <title>" ++ Title ++ "</title>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>
+ " ++ docb_util:html_snippet(head, Opts) ++ "
+ <style type=\"text/css\">
+<!--
+ body { font-family: Verdana, Arial, Helvetica, sans-serif }
+ span.bold_code { font-family: courier;font-weight: bold}
+ span.code { font-family: courier;font-weight: normal}
+
+.note, .warning {
+ border: solid black 1px;
+ margin: 1em 3em;
+}
+
+.note .label {
+ background: #30d42a;
+ color: white;
+ font-weight: bold;
+ padding: 5px 10px;
+}
+.note .content {
+ background: #eafeea;
+ color: black;
+ line-height: 120%;
+ font-size: 90%;
+ padding: 5px 10px;
+}
+.warning .label {
+ background: #C00;
+ color: white;
+ font-weight: bold;
+ padding: 5px 10px;
+}
+.warning .content {
+ background: #FFF0F0;
+ color: black;
+ line-height: 120%;
+ font-size: 90%;
+ padding: 5px 10px;
+}
+
+ .example { background-color:#eeeeff }
+ pre { font-family: courier; font-weight: normal }
+ .REFBODY { margin-left: 13mm }
+ .REFTYPES { margin-left: 8mm }
+-->
+ </style>
+</head>
+<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" vlink=\"#FF00FF\" alink=\"#FF0000\">
+".
+
+ref_html_header(Title, Opts) ->
+ Vsn = docb_util:version(),
+%%"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
+"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<!-- This document was generated using DocBuilder-" ++ Vsn ++ " -->
+<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
+<head>
+ <title>" ++ Title ++ "</title>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>
+ " ++ docb_util:html_snippet(head, Opts) ++ "
+ <style type=\"text/css\">
+<!--
+ body { font-family: Verdana, Arial, Helvetica, sans-serif }
+ span.bold_code { font-family: courier;font-weight: bold}
+ span.code { font-family: courier;font-weight: normal}
+
+.note, .warning {
+ border: solid black 1px;
+ margin: 1em 3em;
+}
+
+.note .label {
+ background: #30d42a;
+ color: white;
+ font-weight: bold;
+ padding: 5px 10px;
+}
+.note .content {
+ background: #eafeea;
+ color: black;
+ line-height: 120%;
+ font-size: 90%;
+ padding: 5px 10px;
+}
+.warning .label {
+ background: #C00;
+ color: white;
+ font-weight: bold;
+ padding: 5px 10px;
+}
+.warning .content {
+ background: #FFF0F0;
+ color: black;
+ line-height: 120%;
+ font-size: 90%;
+ padding: 5px 10px;
+}
+
+ .example { background-color:#eeeeff }
+ pre { font-family: courier; font-weight: normal }
+ .REFBODY { margin-left: 13mm }
+ .REFTYPES { margin-left: 8mm }
+-->
+ </style>
+</head>
+<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" vlink=\"#FF00FF\" alink=\"#FF0000\">
+".
+
+version(Opts, Vsn0) ->
+ case docb_util:lookup_option(vsn, Opts, Vsn0) of
+ "" -> "";
+ Vsn -> " Version " ++ Vsn
+ end.
+
+top_index(Opts) ->
+ case docb_util:lookup_option(top, Opts) of
+ false -> "";
+ TIFile ->
+ " | <a target=\"_top\" href=\"" ++ TIFile ++ "\">Top</a>"
+ end.
diff --git a/lib/docbuilder/src/docb_html_ref.erl b/lib/docbuilder/src/docb_html_ref.erl
new file mode 100644
index 0000000000..c5c166f1ae
--- /dev/null
+++ b/lib/docbuilder/src/docb_html_ref.erl
@@ -0,0 +1,79 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_html_ref).
+
+-export([rule/2, rule/3]).
+
+rule([description|_],_) ->
+ {"\n<h3>DESCRIPTION</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([funcs|_],_) ->
+ {"\n<h3>EXPORTS</h3>\n",""};
+
+rule([func|_],_) ->
+ {"\n<p>",""};
+
+rule([name, func, funcs, RefType|_], {_,_,[{pcdata,[],Name0}]}) ->
+ Name1 = docb_html_util:make_anchor_name_short(Name0, RefType),
+ {"<a name=\"" ++ Name1 ++ "\"><span class=\"bold_code\">",
+ "</span></a><br/>\n"};
+
+rule([fsummary|_],_) ->
+ {drop, "\n</p>\n"};
+
+rule([type|_], _) ->
+ {"\n<div class=\"REFBODY\"><p>Types:</p>\n <div class=\"REFTYPES\">\n<p>\n",
+ "\n </p> </div>\n</div>\n"};
+
+rule([v|_], _) ->
+ {"<span class=\"bold_code\">","</span><br/>\n"};
+
+rule([d|_], _) ->
+ {"\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([desc|_], _) ->
+ {"\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([authors|_], _) ->
+ {"\n<h3>AUTHORS</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([aname|_], _) ->
+ {"", " - "};
+
+rule([section|_], {1,_,_}) ->
+ {"", ""};
+rule([section|_], {_N,_,_}) ->
+ {"", "\n</div>\n"};
+
+rule([title|_], _) ->
+ {"\n<h3>", "</h3>\n<div class=\"REFBODY\">\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html:rule(TagHistory, TagBody).
+
+rule([email|_], _, Opts) ->
+ case docb_util:html_snippet(email, Opts) of
+ "" ->
+ {{"","<br/>\n"}, Opts};
+ Email ->
+ {{drop, Email++"<br/>\n"}, Opts}
+ end;
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html:rule(TagHistory, TagBody, Opts).
+
diff --git a/lib/docbuilder/src/docb_html_util.erl b/lib/docbuilder/src/docb_html_util.erl
new file mode 100644
index 0000000000..b2951706ea
--- /dev/null
+++ b/lib/docbuilder/src/docb_html_util.erl
@@ -0,0 +1,543 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_html_util).
+
+-export([attribute_cdata_to_html/1,
+ element_cdata_to_html/1,
+ pcdata_to_html/1, pcdata_to_html/2]).
+-export([copy_pics/3]).
+-export([extract_header_data/2, all_header_data/1]).
+-export([make_uri/1,
+ make_anchor_href/1, make_anchor_href_short/3,
+ make_anchor_name_short/2,
+ make_funcdef_short/2]).
+-export([erl_include/2, code_include/2, erl_eval/1]).
+-export([number/3, count_sections/1]).
+-export([format_toc/1]).
+-export([html_latin1_sort_order/1]).
+
+%%--Handle CDATA and PCDATA---------------------------------------------
+
+%% NB: Functions for transforming sgmls/XMerL data output to html.
+%% Do not use these for included text files (cf code_include and
+%% erl_include).
+
+attribute_cdata_to_html(Data) ->
+ data2html(Data, false).
+
+element_cdata_to_html(Data) ->
+ data2html(Data, false).
+
+pcdata_to_html(Data) ->
+ data2html(Data, true).
+
+pcdata_to_html(Data, RmSp) ->
+ data2html(Data, RmSp).
+
+%% PCDATA, CDATA: Replace entities, and optionally delete
+%% leading and multiple spaces. CDATA never contains entities to
+%% replace.
+
+%% data2html(Cs, RmSpace)
+data2html([246| Cs], RmSp) ->
+ [$&, $#, $2, $4, $6, $;| data2html(Cs, RmSp)];
+data2html([$>| Cs], RmSp) ->
+ [$&, $#, $6, $2, $;| data2html(Cs, RmSp)];
+data2html([$<| Cs], RmSp) ->
+ [$&, $#, $6, $0, $;| data2html(Cs, RmSp)];
+data2html([$&| Cs], RmSp) ->
+ [$&, $#, $3, $8, $;| data2html(Cs, RmSp)];
+data2html([$\"| Cs], RmSp) ->
+ [$&, $#, $3, $4, $;| data2html(Cs, RmSp)];
+data2html([$\n| Cs], RmSp) ->
+ data2html(Cs, RmSp);
+data2html([$\\, $n| Cs], false) ->
+ [$\n| data2html(Cs, false)];
+data2html([$\\, $n| Cs], true) ->
+ [$\n| data2html(delete_leading_space(Cs), true)];
+data2html([$ , $ | Cs], true) -> % delete multiple space
+ [$ | data2html(delete_leading_space(Cs), true)];
+data2html([$\\, $|| Cs0], RmSp) ->
+ {Ent, Cs1} = collect_entity(Cs0),
+ [entity_to_html(Ent)| data2html(Cs1, RmSp)];
+data2html([$\\, $0, $1, $2| Cs], RmSp) ->
+ data2html(Cs, RmSp);
+data2html([$\\, $\\, $n| Cs], RmSp) ->
+ [$\\, $n| data2html(Cs, RmSp)];
+data2html([$\\, O1, O2, O3| Cs], RmSp)
+ when O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
+ case octal2dec(O1, O2, O3) of
+ 173 -> % soft hyphen
+ data2html(Cs, RmSp);
+ C when C > 31, C < 256 ->
+ Ent = io_lib:format("&#~w;", [C]),
+ [Ent| data2html(Cs, RmSp)];
+ C ->
+ [C| data2html(Cs, RmSp)]
+ end;
+data2html([$\\, $\\| Cs], RmSp) ->
+ [$\\| data2html(Cs, RmSp)];
+data2html([C| Cs], RmSp) ->
+ [C| data2html(Cs, RmSp)];
+data2html([], _) ->
+ [].
+
+delete_leading_space([$ | Cs]) ->
+ delete_leading_space(Cs);
+delete_leading_space(Cs) ->
+ Cs.
+
+collect_entity(Data) ->
+ collect_entity(Data, []).
+
+collect_entity([$\\, $|| Cs], Rs) ->
+ {lists:reverse(Rs), Cs};
+collect_entity([C| Cs], Rs) ->
+ collect_entity(Cs, [C| Rs]);
+collect_entity([], Rs) ->
+ {[], lists:reverse(Rs)}.
+
+entity_to_html("&") -> "&#38;";
+entity_to_html("\"") -> "&#34;";
+entity_to_html("<") -> "&#60;";
+entity_to_html(">") -> "&#62;";
+entity_to_html([$\\, O1, O2, O3])
+ when O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
+ case octal2dec(O1, O2, O3) of
+ 173 -> % soft hyphen
+ "";
+ Value ->
+ io_lib:format("&#~w;", [Value])
+ end;
+entity_to_html(Other) ->
+ docb_html_util_iso:entity_to_html(Other).
+
+octal2dec(O1, O2, O3) ->
+ (O1*8+O2)*8+O3-73*$0.
+
+%%--Copy images---------------------------------------------------------
+
+copy_pics(Src, Dest, Opts) ->
+ Dir = code:lib_dir(docbuilder),
+ InFile = filename:join([Dir, "etc", Src]),
+ OutFile = docb_util:outfile(Dest, "", Opts),
+
+ case filelib:last_modified(OutFile) of
+ 0 -> % File doesn't exist
+ file:copy(InFile, OutFile);
+
+ OutMod2 ->
+ InMod1s = calendar:datetime_to_gregorian_seconds(
+ filelib:last_modified(InFile)),
+ OutMod2s = calendar:datetime_to_gregorian_seconds(OutMod2),
+ if
+ InMod1s > OutMod2s -> % InFile is newer than OutFile
+ file:copy(InFile, OutFile);
+ true ->
+ ok
+ end
+ end.
+
+%%--Resolve header data-------------------------------------------------
+
+extract_header_data(Key, {header, [], List}) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, [], []}} ->
+ "";
+ {value, {Key, [], [{pcdata, [], Value}]}} ->
+ pcdata_to_html(Value);
+ false ->
+ ""
+ end.
+
+all_header_data(Header) ->
+ all_header_data(Header,
+ [title, prepared, responsible, docno, approved,
+ checked, date, rev, file]).
+
+all_header_data(_Header, []) ->
+ [];
+all_header_data(Header, [Key| Rest]) ->
+ [extract_header_data(Key, Header) | all_header_data(Header, Rest)].
+
+%%--Resolve hypertext references----------------------------------------
+
+%% URI regular expression (RFC 2396):
+%% "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"
+%% We split it in five parts:
+%% scheme: "^(([^:/?#]+):)?" (includes trailing `:')
+%% authority: "^(//([^/?#]*))?" (includes leading `//')
+%% path: "^([^?#]*)"
+%% query: "^(\\?([^#]*))?" (includes leading `?')
+%% fragment: "^(#(.*))?" (includes leading `#')
+
+make_uri(Cs) ->
+ lists:flatmap(
+ fun({path, S}) ->
+ case regexp:match(S, "\.xml?\$") of
+ {match, _, _} ->
+ {ok, NS, _} = regexp:sub(S, "\.xml?\$", ".html"),
+ NS;
+ _ ->
+ S
+ end;
+ ({_, S}) ->
+ S
+ end,
+ split_uri(Cs)).
+
+split_uri(URI) ->
+ split_uri(URI, [{scheme, "^(([^:/?#]+):)?"},
+ {authority, "^(//([^/?#]*))?"},
+ {path, "^([^?#]*)"},
+ {'query', "^(\\?([^#]*))?"},
+ {fragment, "^(#(.*))?"}]).
+
+split_uri("", [{Tag, _R}| T]) ->
+ [{Tag, ""}| split_uri("", T)];
+split_uri(Cs0, [{Tag, R}| T]) ->
+ {match, 1, N} = regexp:match(Cs0, R),
+ Cs1 = string:substr(Cs0, 1, N),
+ Cs2 = strip_and_escape_uri_component(Tag, Cs1),
+ [{Tag, Cs2}| split_uri(string:substr(Cs0, N+1), T)];
+split_uri(_, []) ->
+ [].
+
+strip_and_escape_uri_component(authority, "//" ++ Cs) ->
+ "//" ++ escape_uri(string:strip(Cs));
+strip_and_escape_uri_component(path, Cs) ->
+ escape_uri(string:strip(Cs));
+strip_and_escape_uri_component('query', "?" ++ Cs) ->
+ "?" ++ escape_uri(string:strip(Cs));
+strip_and_escape_uri_component(fragment, "#" ++ Cs) ->
+ "#" ++ escape_uri(string:strip(Cs));
+strip_and_escape_uri_component(_, "") ->
+ "";
+strip_and_escape_uri_component(_, Cs) ->
+ escape_uri(string:strip(Cs)).
+
+escape_uri([C|Cs]) when C =< 32;
+ C == $<; C == $<; C == $#; C == $%; C == $";
+ C == $?;
+ C == ${; C == $}; C ==$|; C == $\\; C == $^;
+ C == $[; C == $]; C ==$';
+ C >= 127 ->
+ [$%, mk_hex(C div 16), mk_hex(C rem 16)| escape_uri(Cs)];
+escape_uri([C|Cs]) ->
+ [C|escape_uri(Cs)];
+escape_uri([]) ->
+ [].
+
+mk_hex(C) when C<10 ->
+ C + $0;
+mk_hex(C) ->
+ C - 10 + $a.
+
+make_anchor_href(HRef) ->
+ case regexp:split(HRef, "#") of
+ {ok, [HRef]} ->
+ %% No `#' in HRef, i.e. only path
+ make_anchor_href(HRef, "");
+ {ok, [Path, Fragment]}->
+ make_anchor_href(Path, Fragment)
+ end.
+
+make_anchor_href(Path0, Frag0) ->
+ Frag1 = string:strip(Frag0),
+ Path1 = case Path0 of
+ "" ->
+ "";
+ _ ->
+ case regexp:match(Path0, "\.xml?\$") of
+ nomatch ->
+ Path0 ++ ".html";
+ _ ->
+ {ok, NewPath, _} = regexp:sub(Path0,
+ "\.xml?\$",
+ ".html"),
+ NewPath
+ end
+ end,
+ case Frag1 of
+ "" ->
+ attribute_cdata_to_html(Path1);
+ _ ->
+ attribute_cdata_to_html(Path1) ++
+ "#" ++
+ attribute_cdata_to_html([case Ch of $/ -> $-; _ -> Ch end||
+ Ch <-Frag1])
+ end.
+
+make_anchor_href_short(Path, Frag, RefType) ->
+ ShortFrag = make_funcdef_short(Frag, RefType,"-"),
+ make_anchor_href(Path, ShortFrag).
+
+make_anchor_name_short(FuncName0, RefType) ->
+ FuncName1 = make_funcdef_short(FuncName0, RefType,"-"),
+ attribute_cdata_to_html(FuncName1).
+
+make_funcdef_short(FuncDef0, RefType) ->
+ make_funcdef_short(FuncDef0, RefType, "/").
+
+make_funcdef_short(FuncDef0, RefType,Delimiter) ->
+ FuncDef1 = docb_util:trim(FuncDef0),
+ Any0 = case lists:member(RefType, [cref, erlref]) of
+ true ->
+ case catch docb_util:fknidx(FuncDef1, Delimiter) of
+ {'EXIT', _} ->
+ false;
+ Any1 ->
+ Any1
+ end;
+ false ->
+ false
+ end,
+ case Any0 of
+ false ->
+ case string:tokens(FuncDef1, " ") of
+ [Any2| _] ->
+ Any2;
+ _ ->
+ FuncDef1
+ end;
+ _ ->
+ Any0
+ end.
+
+%%--Include tags--------------------------------------------------------
+
+%% Only used in report DTD
+erl_include(File, Tag) ->
+ case docb_main:include_file(File, Tag) of
+ {ok, Cs} ->
+ {drop, "\n<pre>\n" ++ text_to_html(Cs) ++ "\n</pre>\n"};
+ error ->
+ {drop, ""}
+ end.
+
+code_include(File, Tag) ->
+ case docb_main:include(File, Tag, Tag) of
+ {ok, Cs} ->
+ {ok,text_to_html(Cs)};
+ error ->
+ {error, {codeinclude,File}}
+ end.
+
+erl_eval(Expr) ->
+ Cs = docb_main:eval_str(Expr),
+ {drop, "\n<pre>\n" ++ text_to_html(Cs) ++ "\n</pre>\n"}.
+
+%% Only replaces certain characters. Spaces and new lines etc are kept.
+%% Used for plain text (e.g. inclusions of code).
+text_to_html([$>| Cs]) ->
+ [$&, $#, $6, $2, $;| text_to_html(Cs)];
+text_to_html([$<| Cs]) ->
+ [$&, $#, $6, $0, $;| text_to_html(Cs)];
+text_to_html([$&| Cs]) ->
+ [$&, $#, $3, $8, $;| text_to_html(Cs)];
+text_to_html([$\"| Cs]) ->
+ [$&, $#, $3, $4, $;| text_to_html(Cs)];
+text_to_html([C| Cs]) ->
+ [C| text_to_html(Cs)];
+text_to_html([]) ->
+ [].
+
+%%--Number sections-----------------------------------------------------
+
+number({Tag, Attrs, More}, none, File) ->
+ {Tag, Attrs, do_number(More, [1], File)};
+number({Tag, Attrs, More}, Prefix, File) ->
+ {Tag, Attrs, do_number(More, [list_to_integer(Prefix)], File)}.
+
+do_number([], _, _) ->
+ [];
+do_number([{header, Attrs, More}| Rest], NN, File) ->
+ [{header, Attrs, More}| do_number(Rest, NN, File)];
+do_number([{section, Attrs, More}| Rest], [N| NN], File) ->
+ [{section, Attrs, do_number(More, [1, N| NN], File)}|
+ do_number(Rest, [N+1| NN], File)];
+do_number([{title, _, [{pcdata, _, Title}]}| More], [N| NN], File) ->
+ Format = make_format(length(NN)),
+ Number = lists:flatten(io_lib:format(Format, lists:reverse(NN))),
+ [{marker, [{"ID", "CDATA", Number}], []},
+ {title, [{"NUMBER", "CDATA", Number},
+ {"FILE", "CDATA", File}],
+ [{pcdata, [], Title}]}| do_number(More, [N| NN], File)];
+do_number([{pcdata, Attrs, More}| Rest], NN, File) ->
+ [{pcdata, Attrs, More}| do_number(Rest, NN, File)];
+do_number([{Tag, Attrs, More}| Rest], NN, File) ->
+ [{Tag, Attrs, do_number(More, NN, File)}|do_number(Rest, NN, File)].
+
+make_format(1) ->
+ "~w";
+make_format(N) ->
+ "~w." ++ make_format(N-1).
+
+count_sections([section| Rest]) ->
+ 1 + count_sections(Rest);
+count_sections([_| Rest]) ->
+ count_sections(Rest);
+count_sections([]) ->
+ 0.
+
+%%--Make a ToC----------------------------------------------------------
+
+format_toc(Toc) ->
+ lists:map(fun({Number, Title}) ->
+ [Number, " <a href = \"#", Number,
+ "\">", Title, "</a><br/>\n"]
+ end, Toc).
+
+%%--Convert HTML ISO Latin 1 characters to ordinary characters----------
+
+%% To be used for sorting. Cs must be flat.
+html_latin1_sort_order(Cs) ->
+ hlso(Cs).
+
+hlso([]) ->
+ [];
+hlso([$&, $#, C2, C1, C0, $;| Cs])
+ when $0 =< C2, C2 =< $9, $0 =< C1, C1 =< $9, $0 =< C0, C0 =< $9 ->
+ C = ((C2-$0)*10 + (C1-$0))*10 + C0-$0,
+ hlso0(C, Cs);
+hlso([$&, $#, C1, C0, $;| Cs])
+ when $0 =< C1, C1 =< $9, $0 =< C0, C0 =< $9 ->
+ C = (C1-$0)*10 + C0-$0,
+ hlso0(C, Cs);
+hlso([C| Cs]) ->
+ [C| hlso(Cs)].
+
+hlso0(C, Cs) when 0 =< C, C =< 159 ->
+ [C| hlso(Cs)];
+hlso0(160, Cs) -> %% no-break space
+ hlso(Cs); % Remove it.
+hlso0(161, Cs) -> %% inverted exclamation mark
+ [$? |hlso(Cs)];
+hlso0(162, Cs) -> %% cent sign
+ [$$|hlso(Cs)];
+hlso0(163, Cs) -> %% pound sterling sign
+ [$$|hlso(Cs)];
+hlso0(164, Cs) -> %% general currency sign
+ [$$|hlso(Cs)];
+hlso0(165, Cs) -> %% yen sign
+ [$$|hlso(Cs)];
+hlso0(166, Cs) -> %% broken (vertical) bar
+ [$| |hlso(Cs)];
+hlso0(167, Cs) -> %% section sign
+ [$$|hlso(Cs)];
+hlso0(168, Cs) -> %% umlaut (dieresis)
+ [$: |hlso(Cs)];
+hlso0(169, Cs) -> %% copyright sign
+ [$c |hlso(Cs)];
+hlso0(170, Cs) -> %% ordinal indicator, feminine
+ [$f |hlso(Cs)];
+hlso0(171, Cs) -> %% angle quotation mark, left
+ [$" |hlso(Cs)];
+hlso0(172, Cs) -> %% not sign
+ [$- |hlso(Cs)];
+hlso0(173, Cs) -> %% soft hyphen
+ [$- |hlso(Cs)];
+hlso0(174, Cs) -> %% registered sign
+ [$r |hlso(Cs)];
+hlso0(175, Cs) -> %% macron
+ [$- |hlso(Cs)];
+hlso0(176, Cs) -> %% degree sign
+ [$d |hlso(Cs)];
+hlso0(177, Cs) -> %% plus-or-minus sign
+ [$+ |hlso(Cs)];
+hlso0(178, Cs) -> %% superscript two
+ [$2 |hlso(Cs)];
+hlso0(179, Cs) -> %% superscript three
+ [$3 |hlso(Cs)];
+hlso0(180, Cs) -> %% acute accent
+ [$' |hlso(Cs)];
+hlso0(181, Cs) -> %% micro sign
+ [$' |hlso(Cs)];
+hlso0(182, Cs) -> %% pilcrow (paragraph sign)
+ [$$|hlso(Cs)];
+hlso0(183, Cs) -> %% middle dot
+ [$. |hlso(Cs)];
+hlso0(184, Cs) -> %% cedilla
+ [$c |hlso(Cs)];
+hlso0(185, Cs) -> %% superscript one
+ [$1 |hlso(Cs)];
+hlso0(186, Cs) -> %% ordinal indicator, masculine
+ [$m |hlso(Cs)];
+hlso0(187, Cs) -> %% angle quotation mark, right
+ [$" |hlso(Cs)];
+hlso0(188, Cs) -> %% fraction one-quarter
+ [$4 |hlso(Cs)];
+hlso0(189, Cs) -> %% fraction one-half
+ [$2 |hlso(Cs)];
+hlso0(190, Cs) -> %% fraction three-quarters
+ [$3 |hlso(Cs)];
+hlso0(191, Cs) -> %% inverted question mark
+ [$? |hlso(Cs)];
+
+hlso0(C, Cs) when 192 =< C, C =< 198 -> %% capital A
+ [$A |hlso(Cs)];
+hlso0(199, Cs) -> %% capital C, cedilla
+ [$C |hlso(Cs)];
+hlso0(C, Cs) when 200 =< C, C =< 203 -> %% capital E
+ [$E |hlso(Cs)];
+hlso0(C, Cs) when 204 =< C, C =< 207 -> %% capital I
+ [$I |hlso(Cs)];
+hlso0(208, Cs) -> %% capital Eth, Icelandic
+ [$D |hlso(Cs)];
+hlso0(209, Cs) -> %% capital N, tilde
+ [$N |hlso(Cs)];
+hlso0(C, Cs) when 210 =< C, C =< 214 -> %% capital O
+ [$O |hlso(Cs)];
+hlso0(215, Cs) -> %% multiply sign
+ [$x |hlso(Cs)];
+hlso0(216, Cs) -> %% capital O, slash
+ [$O |hlso(Cs)];
+hlso0(C, Cs) when 217 =< C, C =< 220 -> %% capital U
+ [$U |hlso(Cs)];
+hlso0(221, Cs) -> %% capital Y, acute accent
+ [$Y |hlso(Cs)];
+hlso0(222, Cs) -> %% capital THORN, Icelandic
+ [$T |hlso(Cs)];
+hlso0(223, Cs) -> %% small sharp s, German (sz
+ [$s |hlso(Cs)];
+hlso0(C, Cs) when 224 =< C, C =< 230-> %% small a
+ [$a |hlso(Cs)];
+hlso0(231, Cs) -> %% small c, cedilla
+ [$c |hlso(Cs)];
+hlso0(C, Cs) when 232 =< C, C =< 235 -> %% small e
+ [$e |hlso(Cs)];
+hlso0(C, Cs) when 236 =< C, C =< 239 -> %% small i
+ [$i |hlso(Cs)];
+hlso0(240, Cs) -> %% small eth, Icelandic
+ [$d |hlso(Cs)];
+hlso0(241, Cs) -> %% small n, tilde
+ [$n |hlso(Cs)];
+hlso0(C, Cs) when 242 =< C, C =< 246 -> %% small o
+ [$o |hlso(Cs)];
+hlso0(247, Cs) -> %% divide sign
+ [$/ |hlso(Cs)];
+hlso0(248, Cs) -> %% small o, slash
+ [$o |hlso(Cs)];
+hlso0(C, Cs) when 249 =< C, C =< 252 -> %% small u
+ [$u |hlso(Cs)];
+hlso0(253, Cs) -> %% small y, acute accent
+ [$y |hlso(Cs)];
+hlso0(254, Cs) -> %% small thorn, Icelandic
+ [$t |hlso(Cs)];
+hlso0(255, Cs) -> %% small y, dieresis or umlaut
+ [$y |hlso(Cs)].
diff --git a/lib/docbuilder/src/docb_html_util_iso.erl b/lib/docbuilder/src/docb_html_util_iso.erl
new file mode 100644
index 0000000000..c836805cd2
--- /dev/null
+++ b/lib/docbuilder/src/docb_html_util_iso.erl
@@ -0,0 +1,204 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_html_util_iso).
+-export([entity_to_html/1]).
+
+%% Encodes ISOtech, ISOnum and ISOgrk3.
+%%
+%% All entities are of the form "[abcdef]".
+%%
+entity_to_html(Entity) when is_list(Entity), hd(Entity) =/= $[ ->
+ Entity;
+entity_to_html(Entity) ->
+ case (catch enc(Entity)) of
+ {'EXIT', _} ->
+ Entity;
+ Enc ->
+ "<font face=symbol>" ++ Enc ++ "</font>"
+ end.
+
+enc("[Delta ]") -> "&#68;";
+%% enc("[Dot ]") -> "&#0;";
+%% enc("[DotDot]") -> "&#0;";
+enc("[Gamma ]") -> "&#71;";
+enc("[Lambda]") -> "&#76;";
+enc("[Omega ]") -> "&#87;";
+enc("[Phi ]") -> "&#70;";
+enc("[Pi ]") -> "&#80;";
+enc("[Prime ]") -> "&#178;";
+enc("[Psi ]") -> "&#89;";
+enc("[Sigma ]") -> "&#83;";
+enc("[Theta ]") -> "&#81;";
+enc("[Upsi ]") -> "&#161;";
+%% enc("[Verbar]") -> "&#0;";
+enc("[Xi ]") -> "&#88;";
+
+enc("[aleph ]") -> "&#192;";
+enc("[alpha ]") -> "&#97;";
+enc("[amp ]") -> "&#38;";
+enc("[and ]") -> "&#217;";
+enc("[ang ]") -> "&#208;";
+%% enc("[ang90 ]") -> "&#0;";
+%% enc("[angsph]") -> "&#0;";
+%% enc("[angst ]") -> "&#0;";
+enc("[ap ]") -> "&#187;";
+
+%% enc("[becaus]") -> "&#0;";
+%% enc("[bernou]") -> "&#0;";
+enc("[bepsi ]") -> "&#39;";
+enc("[beta ]") -> "&#98;";
+enc("[bottom]") -> "&#94;";
+enc("[bull ]") -> "&#183;";
+
+enc("[cap ]") -> "&#199;";
+enc("[chi ]") -> "&#99;";
+enc("[clubs ]") -> "&#167;";
+%% enc("[compfn]") -> "&#0;";
+enc("[cong ]") -> "&#64;";
+enc("[copy ]") -> "&#211;";
+%% enc("[conint]") -> "&#0;";
+enc("[cup ]") -> "&#200;";
+
+enc("[dArr ]") -> "&#223;";
+enc("[darr ]") -> "&#175;";
+enc("[deg ]") -> "&#176;";
+enc("[delta ]") -> "&#100;";
+enc("[diam ]") -> "&#224;";
+enc("[diams ]") -> "&#168;";
+enc("[divide]") -> "&#184;";
+
+enc("[empty ]") -> "&#198;";
+%% enc("[epsi ]") -> "&#0;";
+%% enc("[epsis ]") -> "&#0;";
+enc("[epsiv ]") -> "&#101;";
+enc("[equiv ]") -> "&#186;";
+enc("[eta ]") -> "&#104;";
+enc("[exist ]") -> "&#36;";
+
+enc("[fnof ]") -> "&#166;";
+enc("[forall]") -> "&#34;";
+
+enc("[gamma ]") -> "&#103;";
+%% enc("[gammad]") -> "&#0;";
+enc("[ge ]") -> "&#179;";
+enc("[gt ]") -> "&#62;";
+
+%% enc("[hamilt]") -> "&#0;";
+enc("[hArr ]") -> "&#219;";
+enc("[harr ]") -> "&#171;";
+enc("[hearts]") -> "&#169;";
+enc("[horbar]") -> "&#190;";
+
+enc("[iff ]") -> "&#219;";
+enc("[image ]") -> "&#193;";
+enc("[infin ]") -> "&#165;";
+enc("[int ]") -> "&#242;";
+enc("[iota ]") -> "&#105;";
+enc("[isin ]") -> "&#206;";
+
+enc("[kappa ]") -> "&#107;";
+%%enc("[kappav]") -> "&#0;";
+
+enc("[lArr ]") -> "&#220;";
+%% enc("[lagran]") -> "&#0;";
+enc("[lambda]") -> "&#108;";
+enc("[lang ]") -> "&#225;";
+enc("[larr ]") -> "&#172;";
+enc("[le ]") -> "&#163;";
+%% enc("[lowast]") -> "&#0;";
+enc("[lowbar]") -> "&#95;";
+enc("[lt ]") -> "&#60;";
+
+enc("[middot]") -> "&#215;";
+enc("[minus ]") -> "&#45;";
+%% enc("[mnplus]") -> "&#0;";
+enc("[mu ]") -> "&#109;";
+
+enc("[nabla ]") -> "&#209;";
+enc("[ne ]") -> "&#185;";
+enc("[ni ]") -> "&#39;";
+enc("[nsub ]") -> "&#203;";
+enc("[not ]") -> "&#216;";
+enc("[notin ]") -> "&#207;";
+enc("[nu ]") -> "&#110;";
+
+enc("[omega ]") -> "&#119;";
+enc("[or ]") -> "&#218;";
+%% enc("[order ]") -> "&#0;";
+enc("[oplus ]") -> "&#197;";
+enc("[otimes]") -> "&#196;";
+
+%% enc("[par ]") -> "&#0;";
+enc("[part ]") -> "&#182;";
+%% enc("[permil]") -> "&#0;";
+enc("[perp ]") -> "&#94;"; % bottom
+enc("[phis ]") -> "&#102;";
+enc("[phiv ]") -> "&#106;";
+%% enc("[phmmat]") -> "&#0;";
+enc("[pi ]") -> "&#112;";
+enc("[piv ]") -> "&#118;";
+enc("[plus ]") -> "&#43;";
+enc("[plusmn]") -> "&#177;";
+enc("[prime ]") -> "&#162;";
+enc("[prod ]") -> "&#213;";
+enc("[prop ]") -> "&#181;";
+enc("[psi ]") -> "&#121;";
+
+enc("[radic ]") -> "&#214;";
+enc("[rang ]") -> "&#241;";
+enc("[rArr ]") -> "&#222;";
+enc("[rarr ]") -> "&#174;";
+enc("[real ]") -> "&#194;";
+enc("[reg ]") -> "&#210;";
+enc("[rho ]") -> "&#114;";
+%% enc("[rhov ]") -> "&#0;";
+
+enc("[sigma ]") -> "&#115;";
+enc("[sigmav]") -> "&#86;";
+enc("[sim ]") -> "&#126;";
+%% enc("[sime ]") -> "&#0;";
+%% enc("[square]") -> "&#0;";
+enc("[sol ]") -> "&#164;";
+enc("[spades]") -> "&#170;";
+enc("[sub ]") -> "&#204;";
+enc("[sube ]") -> "&#205;";
+enc("[sup ]") -> "&#201;";
+enc("[supe ]") -> "&#202;";
+enc("[sum ]") -> "&#229;";
+
+enc("[tau ]") -> "&#116;";
+enc("[tdot ]") -> "&#188;";
+enc("[there4]") -> "&#92;";
+enc("[thetas]") -> "&#113;";
+enc("[thetav]") -> "&#74;";
+enc("[times ]") -> "&#180;";
+%% enc("[tprime]") -> "&#0;";
+enc("[trade ]") -> "&#212;";
+
+enc("[uArr ]") -> "&#221;";
+enc("[uarr ]") -> "&#173;";
+enc("[upsi ]") -> "&#117;";
+
+enc("[verbar]") -> "&#189;";
+
+%% enc("[wedgeq]") -> "&#0;";
+enc("[weierp]") -> "&#195;";
+
+enc("[xi ]") -> "&#120;";
+
+enc("[zeta ]") -> "&#122;".
diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl
new file mode 100644
index 0000000000..ef21f65557
--- /dev/null
+++ b/lib/docbuilder/src/docb_main.erl
@@ -0,0 +1,651 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_main).
+
+-export([process/2,
+ parse/2, parse1/2,
+ pp/2,
+ insert_after/3,
+ transform/5, pp/5,
+ include_file/2, include/3,
+ eval_str/1,
+ validate_html/1
+ ]).
+-export([do_parse_sgmls/1]).
+
+%%----------------------------------------------------------------------
+
+%% process(File, Opts) -> errors | ok
+%% Parses the source file File and transforms the result to html,
+%% latex and/or man page format.
+process(File, Opts) ->
+
+ File1 = File ++ ".tmpconv",
+ os:cmd("sed -e 's/xi:include[ \t]*href/include file/g' -e 's/xmlns:xi=\"http:\\/\\/www.w3.org\\/2001\\/XInclude\"//g' < " ++
+ File ++ ".xml > " ++ File1 ++ ".xml"), %LATH
+
+ case parse1(File1, Opts) of
+ errors ->
+ file:delete(File1 ++ ".xml"),
+ errors;
+ {ok, Tree} ->
+ From = element(1, Tree),
+ Tos0 =
+ lists:foldl(
+ fun(latex, Acc) -> [latex|Acc];
+ (html, Acc) -> [html|Acc];
+ ({man, _Section}, Acc) -> [man|Acc];
+ (_, Acc) -> Acc
+ end, [], Opts),
+
+ %% If no target format is specified, assume HTML:
+ Tos = if
+ Tos0==[] -> [html];
+ true -> Tos0
+ end,
+
+ Result = [transform(From, To, Opts, File, Tree)||To <- Tos],
+ case lists:member(transformation_error,Result) of
+ true ->
+ file:delete(File1 ++ ".xml"),
+ errors;
+ _ ->
+ file:delete(File1 ++ ".xml"),
+ ok
+ end
+
+ end.
+
+%%----------------------------------------------------------------------
+
+%% parse(File, Opts) -> {ok, Tree} | errors
+%% Parses the source file File, resulting in a tree structure.
+parse(File, Opts) ->
+ case docb_util:lookup_option(src_type, Opts) of
+ ".xml" ->
+ parse_xml(File++".xml", Opts);
+ ".sgml" ->
+ parse_sgml(File, Opts)
+ end.
+
+%% parse1(File, Opts) -> {ok, Tree} | errors
+%% Like parse/2, but in the SGML case also prints the parse errors
+%% (in File.html.sgmls_errs) information to stdout.
+parse1(File, Opts) ->
+ parse(File, [{print_parse_errs, true}|Opts]).
+
+
+validate_html(InFile) ->
+ ScanOpts = [{validation,true}, {fetch_fun, fun fetch_dtd/2}],
+ case xmerl_scan:file(InFile, ScanOpts) of
+ {_XMLTuple,[]} -> % ok
+ {InFile,ok};
+ {'EXIT',Reason} ->
+ {InFile,Reason}
+ end.
+
+fetch_dtd({public,_,"http://www.w3.org/TR/xhtml1/DTD/"++ Rest},GlobalState) ->
+ Filename = filename:join(docb_util:dtd_dir(),Rest),
+ {ok,{file,Filename},GlobalState};
+fetch_dtd({public,_,Str},GlobalState) ->
+ {ok,{file,filename:join(docb_util:dtd_dir(),Str)},GlobalState}.
+
+
+
+parse_xml(InFile, Opts) ->
+ DtdDir = docb_util:dtd_dir(),
+ ScanOpts = [{validation,true}, {fetch_path, [DtdDir]}],
+ PrintP = docb_util:lookup_option(print_parse_errs, Opts),
+ case catch xmerl_scan:file(InFile, ScanOpts) of
+ {'EXIT', Error} when PrintP ->
+ docb_util:message(error,
+ "XML validation error:~n~p", [Error]),
+ errors;
+ {'EXIT', _Error} ->
+ errors;
+ {error, Reason} -> % probably file error
+ docb_util:message(error, "XML scan error: ~p", [Reason]),
+ errors;
+ {Doc, []} ->
+ case catch xmerl:export([Doc], docb_xmerl_tree_cb) of
+ [Tree] ->
+ verify(Tree),
+ {ok, Tree};
+ {'EXIT', Error} ->
+ docb_util:message(error,
+ "XML export error:~n~p", [Error]),
+ errors
+ end
+ end.
+
+parse_sgml(InFile, Opts) ->
+
+ Pfx = tmp_file_prefix(InFile, Opts),
+ OutFile = Pfx ++ "sgmls_output",
+ ErrFile = Pfx ++ "sgmls_errs",
+
+ EntVals = lists:usort(docb_util:lookup_options(ent, Opts)),
+ Ents = lists:flatten([" -ent " ++ Val || Val <- EntVals]),
+ Cmd = docb_util:old_docb_dir() ++ "/bin/docb_sgmls_run " ++
+ Ents ++ " " ++ InFile ++ ".sgml " ++ OutFile ++ " " ++ ErrFile,
+
+ case os:cmd(Cmd) of
+ [] ->
+ PrintP = docb_util:lookup_option(print_parse_errs, Opts),
+ case filelib:file_size(ErrFile) of
+ 0 -> % implies no errors
+ parse_sgmls(InFile, OutFile);
+ _ when PrintP ->
+ cat(ErrFile),
+ errors;
+ _ ->
+ errors
+ end;
+ Msg ->
+ docb_util:message(error, "~p", [Msg]),
+ errors
+ end.
+
+tmp_file_prefix(File, Opts) ->
+ lists:concat(
+ [File, "." | lists:foldl(
+ fun(latex, Acc) -> ["latex."|Acc];
+ (html, Acc) -> ["html."|Acc];
+ ({man, Section}, Acc) -> ["man", Section, "."|Acc];
+ (_, Acc) -> Acc
+ end, [], Opts)]).
+
+parse_sgmls(InFile, SgmlsFile) ->
+ case file:open(SgmlsFile, [read]) of
+ {ok, Fd} ->
+ Res = case (catch do_parse_sgmls(Fd)) of
+ {ok, Tree} ->
+ {ok, Tree};
+ {'EXIT', Reason} ->
+ docb_util:message(
+ error,
+ "Cannot parse sgmls output file "
+ "~s, obtained from parsing ~s, "
+ "reason: ~w",
+ [SgmlsFile, InFile, Reason]),
+ errors;
+ {error, Reason} ->
+ docb_util:message(
+ error,
+ "Cannot parse sgmls output file "
+ "~s, obtained from parsing ~s, "
+ "reason: ~w",
+ [SgmlsFile, InFile, Reason]),
+ errors
+ end,
+ file:close(Fd),
+ case Res of
+ {ok, Tree0} ->
+ verify(Tree0),
+ {ok, Tree0};
+ _Other ->
+ errors
+ end;
+ {error, Reason} ->
+ docb_util:message(error,
+ "Cannot open sgmls output file ~s, "
+ "obtained from parsing ~s, reason: ~w",
+ [SgmlsFile, InFile, Reason]),
+ errors
+ end.
+
+do_parse_sgmls(Fd) ->
+ do_parse_sgmls(Fd, []).
+
+do_parse_sgmls(Fd, Attrs) ->
+ case get_line(Fd) of
+ {attrs, A} ->
+ do_parse_sgmls(Fd, [A|Attrs]);
+ {startTag, Tag} ->
+ {ok, {Tag, Attrs, get_args(Fd)}};
+ Other ->
+ {error, Other}
+ end.
+
+get_args(Fd) ->
+ case get_line(Fd) of
+ {startTag, Tag} ->
+ H = {Tag, [], get_args(Fd)},
+ [H|get_args(Fd)];
+ {dataTag, Str} ->
+ [{pcdata, [], Str}|get_args(Fd)];
+ {attrs, A} ->
+ get_args_attr(Fd, [A]);
+ close ->
+ [];
+ ok ->
+ []
+ end.
+
+get_args_attr(Fd, Attrs) ->
+ case get_line(Fd) of
+ {startTag, Tag} ->
+ H = {Tag, lists:reverse(Attrs), get_args(Fd)},
+ [H|get_args(Fd)];
+ {dataTag, Str} ->
+ [{pcdata, lists:reverse(Attrs), Str}|get_args(Fd)];
+ {attrs, A} ->
+ get_args_attr(Fd, [A|Attrs]);
+ close ->
+ [];
+ ok ->
+ []
+ end.
+
+get_line(Fd) ->
+ Str = io:get_line(Fd, ''),
+ case Str of
+ [$(|T] ->
+ {startTag, tag_name(T)};
+ [$-|T] ->
+ {dataTag, T};
+ [$)|_T] ->
+ close;
+ [$A|T] ->
+ {attrs, attrs(remove_nl(T))};
+ [$?|_T] ->
+ get_line(Fd);
+ [$C|_] ->
+ ok
+ end.
+
+remove_nl([$\n|_]) -> [];
+remove_nl([H|T]) -> [H|remove_nl(T)];
+remove_nl([]) -> [].
+
+%% attrs
+%% splits a string like
+%% AAAAA BBBBB ......
+%% into {"AAA", "BBB", Rest}
+
+attrs(T) ->
+ {X, T1} = get_item(T),
+ {Y, T2} = get_item(T1),
+ T3 = skip_blanks(T2),
+ {X, Y, T3}.
+
+get_item(T) -> get_item(skip_blanks(T), []).
+
+get_item([$ |T], L) -> {lists:reverse(L), [$ |T]};
+get_item([H|T], L) -> get_item(T, [H|L]);
+get_item([], L) -> {lists:reverse(L), []}.
+
+skip_blanks([$ |T]) -> skip_blanks(T);
+skip_blanks(T) -> T.
+
+tag_name(Str) -> tag_name(Str, []).
+
+tag_name([H|T], L) when $A =< H, H =< $Z ->
+ tag_name(T, [H-$A+$a|L]);
+tag_name([$\n], L) ->
+ list_to_atom(lists:reverse(L));
+tag_name([H|T], L) ->
+ tag_name(T, [H|L]).
+
+cat(File) ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ cat1(Fd),
+ file:close(Fd);
+ Other ->
+ Other
+ end.
+
+cat1(Fd) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ eof;
+ Str ->
+ io:format("~s", [Str]),
+ cat1(Fd)
+ end.
+
+%%----------------------------------------------------------------------
+
+verify(Tree) -> verify(Tree, [], 1).
+
+verify({pcdata, Optional, _}, Path, Level) ->
+ verify_optional(Optional, Path, Level);
+verify({Tag, Optional, Args}, Path, Level) when is_list(Args) ->
+ case verify_optional(Optional, Path, Level) of
+ true ->
+ verify_list(Args, [Tag|Path], Level);
+ false ->
+ false
+ end;
+verify(Other, Path, Level) ->
+ verify_error(Other, Path, Level).
+
+verify_error(X, Path, Level) ->
+ docb_util:message(error, "Invalid object found at: ~p level:~w~n~s",
+ [Path, Level, docb_pretty_format:term(X)]),
+ false.
+
+verify_list([H|T], Path, Level) ->
+ case verify(H, Path, Level) of
+ true ->
+ verify_list(T, Path, Level +1);
+ false ->
+ false
+ end;
+verify_list([], _, _) ->
+ true.
+
+verify_optional([{_, _, _}|T], Path, Level) ->
+ verify_optional(T, Path, Level);
+verify_optional([], _Path, _Level) ->
+ true;
+verify_optional(X, Path, Level) ->
+ verify_error(X, Path, Level).
+
+%%----------------------------------------------------------------------
+
+%% pp(File, Opts) -> {ok, OutFile} | errors
+%% Parses the source file and, if successful, prints the resulting tree
+%% structure to a file with the extension ".pp".
+pp(File, Opts) ->
+ case parse(File, Opts) of
+ {ok, Tree} ->
+ OutFile = File ++ ".pp",
+ dump(OutFile, Tree),
+ {ok, OutFile};
+ errors ->
+ errors
+ end.
+
+dump(File, Struct) ->
+ {ok, Stream} = file:open(File, [write]),
+ io:format("Info: Dump on ~p ...", [File]),
+ io:format(Stream, "~n~s~n", [docb_pretty_format:term(Struct)]),
+ io:format(" done.\n"),
+ file:close(Stream).
+
+%%----------------------------------------------------------------------
+
+%% insert_after(Tag, Tree, Obj) -> Tree | {'EXIT', Reason}
+%% Insert an element in a tree structure
+insert_after(Tag, Tree, Obj) ->
+ edit(Tag, Tree, {insert_after, Obj}).
+
+%% edit Op = delete, insert_before, insert_after
+edit(Tag, Tree, Op) ->
+ case catch edit1(Tag, Tree, Op) of
+ error ->
+ docb_util:message(error, "Cannot do ~p to ~w", [Op, Tag]),
+ Tree;
+ Other ->
+ Other
+ end.
+
+edit1(Tag, {Tag, _O, _A}, _Op) ->
+ throw(error);
+edit1(Tag, {Tag1, O, A}, Op) ->
+ {Tag1, O, edit1_list(Tag, A, Op)};
+edit1(_, _, _) ->
+ throw(error).
+
+edit1_list(Tag, [{pcdata, Str}|T], Op) ->
+ [{pcdata, Str}|edit1_list(Tag, T, Op)];
+edit1_list(Tag, [{Tag, O, A}|T], {insert_after, Obj}) ->
+ [{Tag, O, A}, Obj|T];
+edit1_list(Tag, [H|T], Op) ->
+ [H|edit1_list(Tag, T, Op)];
+edit1_list(_Tag, [], _Op) ->
+ [].
+
+%%______________________________________________________________________
+
+%% transform(From, To, Opts, File, Tree) -> void()
+%% Actual transformation of tree structure to desired format.
+transform(From, To, Opts, File, Tree) ->
+ Filter = if
+ To==html; To==kwic ->
+ list_to_atom("docb_tr_" ++ atom_to_list(From) ++
+ [$2|atom_to_list(To)]);
+ true ->
+ list_to_atom("sgml_tr_" ++ atom_to_list(From) ++
+ [$2|atom_to_list(To)])
+ end,
+
+ case catch apply(Filter, transform, [File, Tree, Opts]) of
+
+ %% R5C
+ {'EXIT', {undef, [{Filter, transform, [File, Tree, Opts]}|_]}}->
+ %% No transformation defined
+ finish_transform(Tree, File, Opts, Filter);
+
+ {'EXIT', {undef, {Filter, transform, [File, Tree, Opts]}}} ->
+ %% No transformation defined
+ finish_transform(Tree, File, Opts, Filter);
+
+ {'EXIT', What} ->
+ docb_util:message(error,
+ "Transformation trouble in ~P", [What, 9]),
+ transformation_error;
+
+ {error, Reason} ->
+ docb_util:message(error, Reason),
+ transformation_error;
+
+ {Tree1, Opts1} ->
+ %% transformation returning both new parse and new options
+ finish_transform(Tree1, File, Opts1, Filter);
+
+ Tree1 ->
+ %% transformation returning only new parse
+ finish_transform(Tree1, File, Opts, Filter)
+ end.
+
+finish_transform(Tree, File, Opts, Filter) ->
+ {Str, NewOpts} = pp(Tree, [], 1, Filter, Opts),
+ Extension =
+ case catch apply(Filter, extension, [NewOpts]) of
+ {'EXIT', _} ->
+ apply(Filter, extension, []);
+ Others ->
+ Others
+ end,
+ {ok, Out} =
+ file:open(docb_util:outfile(File, Extension, NewOpts), [write]),
+ put_chars(Out, Str),
+ file:close(Out).
+
+put_chars(Out, Str) -> put_chars(Out, Str, 0).
+
+put_chars(Out, [$\n|Cs], _Pos) ->
+ io:put_chars(Out, [$\n]),
+ put_chars(Out, Cs, 0);
+
+put_chars(Out, [$\011|Cs], Pos) -> % tab
+ TabbedPos = 8*((Pos div 8)+1),
+ Nblanks = TabbedPos - Pos,
+ io:put_chars(Out, lists:duplicate(Nblanks, $ )),
+ put_chars(Out, Cs, Pos+Nblanks);
+
+put_chars(Out, [C|Cs], Pos) when is_integer(C) ->
+ io:put_chars(Out, [C]),
+ put_chars(Out, Cs, Pos+1);
+
+put_chars(Out, [L|Cs], Pos) when is_list(L) ->
+ put_chars(Out, Cs, put_chars(Out, L, Pos));
+
+put_chars(_Out, [], Pos) ->
+ Pos.
+
+pp({Tag, Optional, Args}, TagPath, Level, Filter, Opts) ->
+ TagPath1 = [Tag|TagPath],
+ Optional1 = reduce_optional(Optional),
+
+ %% First try Filter:rule/3. It returns {Return, NewOpts}
+ %% where Return is as from rule/2:
+ Rule_3_result =
+ case catch Filter:rule(TagPath1, {Level,Optional1,Args},Opts) of
+ %% R5C
+ {'EXIT', {undef, [{_, rule, _}|_]}} -> % No rule/3 defined
+ failed;
+
+ {'EXIT', {undef, {_, rule, _}}} -> % No rule/3 defined
+ failed;
+ %% R5C
+ {'EXIT', {function_clause, [{_, rule, _}|_]}} -> % No MATCHING rule/3
+ failed;
+
+ {'EXIT', {function_clause, {_, rule, _}}} -> % No MATCHING rule/3
+ failed;
+
+ {'EXIT', What} ->
+ docb_util:message(error,
+ "Serious Error: ~P", [What, 9]);
+ Others ->
+ Others
+ end,
+ handle_rule_call_result({r3, Rule_3_result}, Filter, TagPath1, Tag,
+ Level, Optional1, Args, Opts).
+
+handle_rule_call_result({r3, failed}, Filter, TagPath1, Tag, Level, Optional1,
+ Args, Opts) ->
+ %% Hmmm, try Filter:rule/2
+ Rule_2_result = (catch Filter:rule(TagPath1, {Level, Optional1, Args})),
+ handle_rule_call_result({r2, Rule_2_result}, Filter, TagPath1, Tag,
+ Level, Optional1, Args, Opts);
+handle_rule_call_result({r3, {Result, NewOpts}}, Filter, TagPath1, Tag, Level,
+ Optional1, Args, _Opts) ->
+ handle_rule_call_result({r2, Result}, Filter, TagPath1, Tag, Level,
+ Optional1, Args, NewOpts);
+handle_rule_call_result({_, {func, F}}, _Filter, _TagPath1, _Tag, _Level,
+ _Optional1, Args, Opts) ->
+ {F(Args), Opts};
+handle_rule_call_result({_, {'EXIT', Why}}, _Filter, TagPath1, _Tag, Level,
+ Optional1, Args, Opts) ->
+ report_error(TagPath1, Why, {Level, Optional1, Args}),
+ {[], Opts};
+handle_rule_call_result({_, {drop, Str}}, _Filter, _TagPath1, _Tag, _Level,
+ _Optional1, _Args, Opts) ->
+ {[Str], Opts};
+handle_rule_call_result({_, {newargs, NewArgs}}, Filter, TagPath1, _Tag, _Level,
+ _Optional1, _Args, Opts) ->
+ {List, NewOpts} = pp_list(NewArgs, TagPath1, 1, Filter, Opts),
+ {[List], NewOpts};
+handle_rule_call_result({_, {newargs, Before, NewArgs, After}}, Filter, TagPath1, _Tag, _Level,
+ _Optional1, _Args, Opts) ->
+ {List, NewOpts} = pp_list(NewArgs, TagPath1, 1, Filter, Opts),
+ {[Before, List, After], NewOpts};
+handle_rule_call_result({_, {Before, After}}, Filter, TagPath1, _Tag, _Level,
+ _Optional1, Args, Opts) when is_list(Before) ->
+ {List, NewOpts} = pp_list(Args, TagPath1, 1, Filter, Opts),
+ {[Before, List, After], NewOpts}.
+
+pp_list([H|T], TagPath, Level, Rules, Opts) ->
+ {Hpp, Hopts} = pp(H, TagPath, Level, Rules, Opts),
+ {Tpp, Tops} = pp_list(T, TagPath, Level + 1, Rules, Hopts),
+ {[Hpp|Tpp], Tops};
+pp_list([], _, _, _, Opts) ->
+ {[], Opts}.
+
+reduce_optional([{_, _, H}|T]) -> [H|reduce_optional(T)];
+reduce_optional([]) -> [].
+
+report_error(Arg1, Cause, Arg2) ->
+ [Tag|_] = Arg1,
+ docb_util:message(error,
+ "Formatting trouble in ~p: ~p", [Tag, Cause]),
+ docb_util:message(error, "Failure in rule(~p, ~p)", [Arg1, Arg2]).
+
+%%----------------------------------------------------------------------
+
+%% include_file(File, Tag) -> {ok, String} | error
+include_file(File, Tag) ->
+ include(File, "%S" ++ Tag, "%E" ++ Tag).
+
+%% include(File, StartTag, StopTag) -> {ok, String} | error
+include(File, "", "") ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ String = include_all(Fd),
+ file:close(Fd),
+ {ok, String};
+ _ ->
+ docb_util:message(error,
+ "Include file ~s not found", [File]),
+ error
+ end;
+include(File, StartTag, StopTag) ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ String = extract(File, Fd, StartTag, StopTag, searching),
+ file:close(Fd),
+ {ok, lists:flatten(String)};
+ _ ->
+ docb_util:message(error,
+ "Include file ~s not found", [File]),
+ error
+ end.
+
+include_all(Fd) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ [];
+ ListOfChars ->
+ lists:append(ListOfChars, include_all(Fd))
+ end.
+
+extract(File, Fd, StartTag, StopTag, State) ->
+ Line=io:get_line(Fd, ''),
+ extract(File, Fd, StartTag, StopTag, State, Line).
+
+extract(File, _, _, _, _, eof) ->
+ docb_util:message(error,
+ "Premature end of file in include file ~p",
+ [File]),
+ [];
+extract(File, Fd, StartTag, StopTag, searching, Line) ->
+ case regexp:match(Line, "^" ++ StartTag) of
+ {match, _Start, _Length} ->
+ extract(File, Fd, StartTag, StopTag, copying);
+ nomatch ->
+ extract(File, Fd, StartTag, StopTag, searching);
+ {error, _Error} ->
+ docb_util:message(error, "Bad syntax in ~s", [File]),
+ []
+ end;
+extract(File, Fd, StartTag, StopTag, copying, Line) ->
+ case regexp:match(Line, "^" ++ StopTag) of
+ {match, _Start, _Length} ->
+ [];
+ nomatch ->
+ [Line|extract(File, Fd, StartTag, StopTag, copying)];
+ {error, _Error} ->
+ docb_util:message(error, "Bad syntax in ~s", [File]),
+ []
+ end.
+
+%%----------------------------------------------------------------------
+
+eval_str(Str) ->
+ case lib:eval_str(Str) of
+ {error, Report} ->
+ docb_util:message(error,
+ "ErlEval failed: ~s (~s)", [Str, Report]);
+ {ok, S} ->
+ io_lib:format("~p~n", [S])
+ end.
diff --git a/lib/docbuilder/src/docb_pretty_format.erl b/lib/docbuilder/src/docb_pretty_format.erl
new file mode 100644
index 0000000000..0c4fb0507b
--- /dev/null
+++ b/lib/docbuilder/src/docb_pretty_format.erl
@@ -0,0 +1,177 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_pretty_format).
+
+-export([term/1]).
+
+%% pretty_format:term(Term) -> PNF list of characters
+%%
+%% Note: this is usually used in expressions like:
+%% io:format('~s\n', [pretty_format:term(Term)]).
+%%
+%% Uses the following simple heuristics:
+%%
+%% 1) Simple tuples are printed across the page.
+%% (Simple means *all* the elements are "flat")
+%% 2) The complex tuple {Arg1, Arg2, Arg3,....} is printed thus:
+%% {Arg1,
+%% Arg2,
+%% Arg3,
+%% ...}
+%% 3) Lists are treated as for tuples.
+%% 4) Lists of printable characters are treated as strings.
+%%
+%% This method seems to work reasonable well for {Tag, ...} type
+%% data structures.
+term(Term) ->
+ element(2, term(Term, 0)).
+
+%% pretty_format:term(Term, Indent} -> {Indent', Chars}
+%% Format <Term> -- use <Indent> to indent the *next* line.
+%% Note: Indent' is a new indentaion level (sometimes printing <Term>
+%% the next line to need an "extra" indent!).
+term([], Indent) ->
+ {Indent, [$[,$]]};
+term(L, Indent) when list(L) ->
+ case is_string(L) of
+ true ->
+ {Indent, io_lib:write_string(L)};
+ false ->
+ case complex_list(L) of
+ true ->
+ write_complex_list(L, Indent);
+ false ->
+ write_simple_list(L, Indent)
+ end
+ end;
+term(T, Indent) when tuple(T) ->
+ case complex_tuple(T) of
+ true ->
+ write_complex_tuple(T, Indent);
+ false ->
+ write_simple_tuple(T, Indent)
+ end;
+term(A, Indent) ->
+ {Indent, io_lib:write(A)}.
+
+%% write_simple_list([H|T], Indent) -> {Indent', Chars}
+write_simple_list([H|T], Indent) ->
+ {_, S1} = term(H, Indent),
+ {_, S2} = write_simple_list_tail(T, Indent),
+ {Indent, [$[,S1|S2]}.
+
+write_simple_list_tail([H|T], Indent) ->
+ {_, S1} = term(H, Indent),
+ {_, S2} = write_simple_list_tail(T, Indent),
+ {Indent, [$,,S1| S2]};
+write_simple_list_tail([], Indent) ->
+ {Indent, "]"};
+write_simple_list_tail(Other, Indent) ->
+ {_, S} = term(Other, Indent),
+ {Indent, [$|,S,$]]}.
+
+%% write_complex_list([H|T], Indent) -> {Indent', Chars}
+write_complex_list([H|T], Indent) ->
+ {I1, S1} = term(H, Indent+1),
+ {_, S2} = write_complex_list_tail(T, I1),
+ {Indent, [$[,S1|S2]}.
+
+write_complex_list_tail([H|T], Indent) ->
+ {I1, S1} = term(H, Indent),
+ {_, S2} = write_complex_list_tail(T, I1),
+ {Indent, [$,,nl_indent(Indent),S1,S2]};
+write_complex_list_tail([], Indent) ->
+ {Indent, "]"};
+write_complex_list_tail(Other, Indent) ->
+ {_, S} = term(Other, Indent),
+ {Indent, [$|,S,$]]}.
+
+%% complex_list(List) -> true | false
+%% Returns true if the list is complex otherwise false.
+complex_list([]) ->
+ false;
+complex_list([H|T]) when is_list(H) ->
+ case is_string(H) of
+ true ->
+ complex_list(T);
+ false ->
+ true
+ end;
+complex_list([H|_]) when is_tuple(H) -> true;
+complex_list(_) -> false.
+
+%% complex_tuple(Tuple) -> true | false
+%% Returns true if the tuple is complex otherwise false.
+complex_tuple(T) ->
+ complex_list(tuple_to_list(T)).
+
+%% write_simple_tuple(Tuple, Indent} -> {Indent', Chars}
+write_simple_tuple({}, Indent) ->
+ {Indent, "{}"};
+write_simple_tuple(Tuple, Indent) ->
+ {_, S} = write_simple_tuple_args(tuple_to_list(Tuple), Indent),
+ {Indent, [${, S, $}]}.
+
+write_simple_tuple_args([X], Indent) ->
+ term(X, Indent);
+write_simple_tuple_args([H|T], Indent) ->
+ {_, SH} = term(H, Indent),
+ {_, ST} = write_simple_tuple_args(T, Indent),
+ {Indent, [SH, $,, ST]}.
+
+%% write_complex_tuple(Tuple, Indent} -> {Indent', Chars}
+write_complex_tuple(Tuple, Indent) ->
+ [H|T] = tuple_to_list(Tuple),
+ {I1, SH} = term(H, Indent+2),
+ {_, ST} = write_complex_tuple_args(T, I1),
+ {Indent, [${, SH, ST, $}]}.
+
+write_complex_tuple_args([X], Indent) ->
+ {_, S} = term(X, Indent),
+ {Indent, [$,, nl_indent(Indent), S]};
+write_complex_tuple_args([H|T], Indent) ->
+ {I1, SH} = term(H, Indent),
+ {_, ST} = write_complex_tuple_args(T, I1),
+ {Indent, [$,, nl_indent(Indent) , SH, ST]};
+write_complex_tuple_args([], Indent) ->
+ {Indent, []}.
+
+%% utilities
+
+nl_indent(I) when I >= 0 ->
+ ["\n"|indent(I)];
+nl_indent(_I) ->
+ [$ ].
+
+indent(I) when I >= 8 ->
+ [$\t|indent(I-8)];
+indent(I) when I > 0 ->
+ [$ |indent(I-1)];
+indent(_) ->
+ [].
+
+is_string([9|T]) ->
+ is_string(T);
+is_string([10|T]) ->
+ is_string(T);
+is_string([H|T]) when H >31, H < 127 ->
+ is_string(T);
+is_string([]) ->
+ true;
+is_string(_) ->
+ false.
diff --git a/lib/docbuilder/src/docb_tr_application2html.erl b/lib/docbuilder/src/docb_tr_application2html.erl
new file mode 100644
index 0000000000..4084cfe6ba
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_application2html.erl
@@ -0,0 +1,288 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_application2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(File, {application, _Attrs, [Header|Rest]}, Opts0) ->
+
+ %% Extract header data
+ Title = docb_html_util:extract_header_data(title, Header),
+
+ case docb_util:an_option(kwicindex_only, Opts0) of
+ false ->
+
+ %% Create the framing HTML document
+ OutFile = docb_util:outfile(File++"_frame", ".html", Opts0),
+ case file:open(OutFile, [write]) of
+ {ok, Fd} ->
+ io:format(Fd,
+"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
+\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
+<!-- This document was generated using DocBuilder-" ++ docb_util:version() ++ " -->
+<html>
+<head>
+ <title>~s</title>
+ " ++ docb_util:html_snippet(head, Opts0) ++ "
+</head>
+<frameset cols=\"150, *\">
+ <frame src=\"~s\" name=\"toc\">
+ <frame src=\"~s\" name=\"document\">
+ <noframes>
+ <body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\"
+ vlink=\"#FF00FF\" alink=\"#FF0000\">
+ <p>This documentation requires a browser that can handle frames</p>
+ </body>
+ </noframes>
+</frameset>
+</html>
+",
+ [Title,
+ File++".html", File++"_first.html"]),
+ file:close(Fd)
+ end,
+
+ %% Create the front HTML document
+ docb_main:transform(first, html, Opts0, File ++ "_first",
+ {first, [], [Header|Rest]});
+
+ true ->
+ ok
+ end,
+
+ %% Extract files to include
+ Files = case Rest of
+ [{description, _, _}|NewRest] ->
+ lists:map(fun({include, [{_, _, F}], _}) ->filename:rootname(F) end,
+ NewRest);
+ [{include, _, _}|_NewRest] ->
+ lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end,
+ Rest)
+ end,
+
+ %% Concat all reference manuals into a *big* parse tree
+ ConcatTree = concat_files(Files, Opts0),
+
+ %% Create the kwic index src file to be put in outdir
+ docb_main:transform(refs, kwic, Opts0, File, {refs,[],ConcatTree}),
+
+ case docb_util:an_option(kwicindex_only, Opts0) of
+ false ->
+
+ %% Create an index
+ docb_main:transform(index, html, Opts0, File ++ "_index",
+ {index, [], [Header|ConcatTree]}),
+ %% Create a cite dictionary
+ docb_main:transform(cite, html, Opts0, File ++ "_cite",
+ {cite, [], [Header|ConcatTree]}),
+
+ %% Create a term dictionary
+ docb_main:transform(term, html, Opts0, File ++ "_term",
+ {term, [], [Header|ConcatTree]}),
+
+ %% Transform each reference page
+ case docb_util:an_option(framework_only, Opts0) of
+ true ->
+ ok;
+ false ->
+ transform_refs(Files,
+ [dict,{part_application,File}|Opts0])
+ end;
+ true ->
+ ok
+ end,
+
+ %% Find all fascicules to be put in the top menu of the table of
+ %% contents
+ Ext = docb_util:lookup_option(src_type, Opts0),
+ Opts2 =
+ case filelib:is_regular("fascicules"++Ext) of
+ true ->
+ case docb_main:parse1("fascicules", Opts0) of
+ {ok, Parse} ->
+ FascData = get_fasc_data(Parse),
+ case lists:keysearch(File, 1, FascData) of
+ {value, {_, _, "YES", _}} ->
+ OrigFile =
+ docb_util:outfile(File++"_frame",
+ ".html", Opts0),
+ EntryFile =
+ docb_util:outfile("index",
+ ".html",Opts0),
+ docb_util:message(info,
+ "Copying ~s to ~s",
+ [OrigFile,EntryFile]),
+ file:copy(OrigFile, EntryFile);
+ _ ->
+ ok
+ end,
+ [{fascdata, FascData}| Opts0];
+ errors ->
+ %% Do not bother
+ docb_util:message(
+ warning,
+ "fascicules~s could not be parsed,"
+ " no index.html created",
+ [Ext]),
+ Opts0
+ end;
+ false ->
+ %% do not bother
+ docb_util:message(warning,
+ "fascicules~s not found, "
+ "no index.html created",
+ [Ext]),
+ Opts0
+ end,
+
+ %% Create ToC parse tree
+ {{toc, [{"FILE", "CDATA", File}], [Header|make_toc(ConcatTree)]},
+ Opts2}.
+
+concat_files(Files, Opts) ->
+ concat_files(Files, [], Opts).
+
+concat_files([File|Rest], Body, Opts) ->
+ case docb_main:parse1(File, Opts) of
+ {ok, Parse} ->
+ NewParse=expand([Parse], File),
+ %% Remove the reference manual header
+ [{Ref, [], [_Hdr| NewBody]}] = NewParse,
+ RefParse = [{Ref, [], NewBody}],
+ lists:append(Body, concat_files(Rest, RefParse, Opts));
+ errors ->
+ errors
+ end;
+concat_files([], Body, _Opts) ->
+ Body.
+
+expand([], _) ->
+ [];
+expand([{pcdata, Attrs, More}|Rest], File) ->
+ [{pcdata, Attrs, More}|expand(Rest, File)];
+expand([{name, Attrs, More}|Rest], File) ->
+ [{name, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
+expand([{module, Attrs, More}|Rest], File) ->
+ [{module, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest,File)];
+expand([{file, Attrs, More}|Rest], File) ->
+ [{file, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
+expand([{app, Attrs, More}|Rest], File) ->
+ [{app, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
+expand([{lib, Attrs, More}|Rest], File) ->
+ [{lib, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
+expand([{com, Attrs, More}|Rest], File) ->
+ [{com, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
+expand([{Tag, Attrs, More}|Rest], File) ->
+ [{Tag, Attrs, expand(More, File)}|expand(Rest, File)].
+
+transform_refs([], _) ->
+ ok;
+transform_refs([File|Rest], Opts) ->
+ Ext = docb_util:lookup_option(src_type, Opts),
+ docb_util:message(info, "Processing \"~s~s\"", [File, Ext]),
+ docb_main:process(File, Opts),
+ transform_refs(Rest, Opts).
+
+make_toc([]) ->
+ [];
+make_toc([{pcdata, _Attrs, _More}|Rest]) ->
+ make_toc(Rest);
+make_toc([{module, Attrs, More}|Rest]) ->
+ [{module, Attrs, More}|make_toc(Rest)];
+make_toc([{file, Attrs, More}|Rest]) ->
+ [{file, Attrs, More}|make_toc(Rest)];
+make_toc([{app, Attrs, More}|Rest]) ->
+ [{app, Attrs, More}|make_toc(Rest)];
+make_toc([{lib, Attrs, More}|Rest]) ->
+ [{lib, Attrs, More}|make_toc(Rest)];
+make_toc([{com, Attrs, More}|Rest]) ->
+ [{com, Attrs, More}|make_toc(Rest)];
+make_toc([{_Tag, _Attrs, More}|Rest]) ->
+ lists:append(make_toc(More), make_toc(Rest)).
+
+rule([module|_], {_, [File], _}) ->
+ {"<small><a target=\"document\" href=\"" ++
+ docb_html_util:make_anchor_href(File) ++ "\">",
+ "</a></small><br/>\n"};
+
+rule([file|_], {_, [File], _}) ->
+ {"<small><a target=\"document\" href=\"" ++
+ docb_html_util:make_anchor_href(File) ++ "\">",
+ "</a></small><br/>\n"};
+
+rule([app|_], {_, [File], _}) ->
+ {"<small><a target=\"document\" href=\"" ++
+ docb_html_util:make_anchor_href(File) ++ "\">",
+ "</a></small><br/>\n"};
+
+rule([lib|_], {_, [File], _}) ->
+ {"<small><a target=\"document\" href=\"" ++
+ docb_html_util:make_anchor_href(File) ++ "\">",
+ "</a></small><br/>\n"};
+
+rule([com|_], {_, [File], _}) ->
+ {"<small><a target=\"document\" href=\"" ++
+ docb_html_util:make_anchor_href(File) ++ "\">",
+ "</a></small><br/>\n"};
+
+rule([pcdata|_], {_, _, Data}) ->
+ {drop, docb_html_util:pcdata_to_html(Data)};
+
+rule(_, _) ->
+ {drop, ""}.
+
+rule([toc|_], {_Depth, [File], [Header|_]}, Opts) ->
+ case docb_util:lookup_option(fascdata, Opts) of
+ false ->
+ {{docb_html_layout:application_toc_top(
+ docb_html_util:all_header_data(Header),
+ File, Opts),
+ docb_html_layout:part_toc_bot()}, Opts};
+ FascData ->
+ HRefTexts =
+ lists:map(
+ fun({_File, HRef, _Entry, PCText}) ->
+ {HRef, docb_html_util:pcdata_to_html(PCText)}
+ end,
+ FascData),
+ {{docb_html_layout:application_toc_top(
+ docb_html_util:all_header_data(Header),
+ File, Opts, HRefTexts) ++ "\n",
+ docb_html_layout:part_toc_bot()}, Opts}
+ end.
+
+%% Returns: [{File, HRef, Entry, Text}].
+get_fasc_data({fascicules, _, Fascs}) ->
+ lists:map(
+ fun({fascicule, Atts, Trees}) ->
+ AVals = get_avals(Atts),
+ PCText = get_pc_text(Trees),
+ list_to_tuple(lists:append([AVals, [PCText]]))
+ end,
+ Fascs).
+
+get_avals(Atts) ->
+ lists:map(fun(Tuple) ->
+ element(3, Tuple) end,
+ Atts).
+
+get_pc_text([{pcdata, _, Text}]) ->
+ Text.
diff --git a/lib/docbuilder/src/docb_tr_appref2html.erl b/lib/docbuilder/src/docb_tr_appref2html.erl
new file mode 100644
index 0000000000..6b4cc0f815
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_appref2html.erl
@@ -0,0 +1,48 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_appref2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+%% Transform the parse tree. Header data is stored in an extra
+%% argument to make life easier later on.
+transform(_File, {appref,_,[Header|Rest]}, _Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ {appref, Data, [{header,[],[]}|Rest]}.
+
+rule([header|_],_) ->
+ {drop, ""};
+
+rule([app|_],_) ->
+ {"\n<h3>APPLICATION</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([appsummary|_],_) ->
+ {"\n<h3>APPLICATION SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html_ref:rule(TagHistory,TagBody).
+
+rule([appref|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:ref_top(Data, Opts),
+ docb_html_layout:ref_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_chapter2html.erl b/lib/docbuilder/src/docb_tr_chapter2html.erl
new file mode 100644
index 0000000000..185cdc7cc3
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_chapter2html.erl
@@ -0,0 +1,59 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_chapter2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(File, {chapter,_,[Header|Rest]}, Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ Tree = {chapter, Data, [{header,[],[]}|Rest]},
+ ChapterLevel =
+ case docb_util:lookup_option(number, Opts) of
+ false -> none;
+ Value -> Value
+ end,
+ docb_html_util:number(Tree, ChapterLevel, File).
+
+rule([header|_], _) ->
+ {drop, ""};
+
+rule([toc|_], {_,_,ToC}) ->
+ {drop,
+ "\n<h3>Table of Contents</h3>\n" ++
+ docb_html_util:format_toc(ToC) ++ "\n"};
+
+rule([section|_], _) ->
+ {"", ""};
+
+rule([title|Rest], {_,[Number,_File], [{pcdata,_,Title}]}) ->
+ N = integer_to_list(docb_html_util:count_sections(Rest)+1),
+ {drop,"\n<h" ++ N ++ ">" ++ Number ++ " " ++
+ docb_html_util:pcdata_to_html(Title) ++ "</h" ++ N ++ ">\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html:rule(TagHistory, TagBody).
+
+rule([chapter|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:chapter_top(Data, Opts),
+ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_cite2html.erl b/lib/docbuilder/src/docb_tr_cite2html.erl
new file mode 100644
index 0000000000..4ecbfa4e91
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_cite2html.erl
@@ -0,0 +1,136 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_cite2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, Tree, Opts) ->
+ purge(Tree, Opts).
+
+purge({Tag, Attrs, [Header|Body]}, Opts) ->
+ CiteList = case docb_util:lookup_option({defs,cite}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ B1 = purge_body(Body, CiteList),
+ B2 = lists:ukeysort(2, B1),
+ {Tag, Attrs, [Header|B2]}.
+
+purge_body([], _) ->
+ [];
+purge_body([{pcdata,_Attrs,_More}|Rest], CiteList) ->
+ purge_body(Rest, CiteList);
+purge_body([{cite,[{"ID","CDATA",ID}],More}|Rest], CiteList) ->
+ case lists:keysearch(ID, 1, CiteList) of
+ false ->
+ [{cite, [{"NAME","CDATA",ID}, {"ID","CDATA",ID}], More}|
+ purge_body(Rest, CiteList)];
+ {value, {ID, Name, _Description, _Responsible}} ->
+ [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
+ purge_body(Rest, CiteList)];
+ {value, {ID, Name, _Description}} ->
+ [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
+ purge_body(Rest, CiteList)]
+ end;
+purge_body([{_Tag,_Attrs,More}|Rest], CiteList) ->
+ lists:append(purge_body(More, CiteList),
+ purge_body(Rest, CiteList)).
+
+rule([header|_], _) ->
+ {drop, ""};
+
+rule(_, _) ->
+ {drop, ""}.
+
+rule([cite|_], {_,[],[Header]}, Opts) ->
+ HeaderData = docb_html_util:all_header_data(Header),
+ {{docb_html_layout:chapter_top(HeaderData, Opts) ++
+ "\n<center><h1>Bibliography</h1></center>\n",
+ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([cite|_], {_,[],[Header|_]}, Opts) ->
+ HeaderData = docb_html_util:all_header_data(Header),
+ {{docb_html_layout:chapter_top(HeaderData, Opts) ++
+ "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
+ "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([cite|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:chapter_top(Data, Opts) ++
+ "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
+ "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([cite|T], {A, B, [{citedef,C,
+ [{ctitle, [], [{pcdata,[],CTitle}]},
+ {cauthor, [], [{pcdata,[],CAuthor}]},
+ {chowpublished, [],
+ [{pcdata,[],Chowpublished}]}]}]}, Opts) ->
+ CiteDef = CTitle ++ " " ++ CAuthor ++ " " ++ Chowpublished,
+ rule([cite|T], {A,B,[{citedef,C,[{pcdata,[],CiteDef}]}]}, Opts);
+
+rule([cite|_], {_,[Name,ID], [{citedef,[],[{pcdata,[],Def}]}]}, Opts) ->
+ CiteList =
+ case docb_util:lookup_option({defs,cite}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ case lists:keysearch(ID, 1, CiteList) of
+ false ->
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
+ {value, {ID, Name, Description, _Responsible}} ->
+ docb_util:message(warning,
+ "Global cite ~s overriding local", [ID]),
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
+ Opts};
+ {value, {ID, Name, Description}} ->
+ docb_util:message(warning,
+ "Global cite ~s overriding local", [ID]),
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
+ end;
+
+rule([cite|_], {_,[Name,ID],_}, Opts) ->
+ CiteList =
+ case docb_util:lookup_option({defs,cite}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ case lists:keysearch(ID, 1, CiteList) of
+ false ->
+ docb_util:message(error,
+ "The cite ~s has no definition", [ID]),
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
+ "??" ++ "\n</dd>\n"}, Opts};
+ {value, {ID, Name, Description, _Responsible}} ->
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
+ Opts};
+ {value, {ID, Name, Description}} ->
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
+ end.
diff --git a/lib/docbuilder/src/docb_tr_comref2html.erl b/lib/docbuilder/src/docb_tr_comref2html.erl
new file mode 100644
index 0000000000..25207dccb4
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_comref2html.erl
@@ -0,0 +1,46 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_comref2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, {comref,_,[Header|Rest]}, _Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ {comref, Data, [{header,[],[]}|Rest]}.
+
+rule([header|_],_) ->
+ {drop,""};
+
+rule([com|_],_) ->
+ {"\n<h3>COMMAND</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([comsummary|_],_) ->
+ {"\n<h3>COMMAND SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html_ref:rule(TagHistory, TagBody).
+
+rule([comref|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:ref_top(Data, Opts),
+ docb_html_layout:ref_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_cref2html.erl b/lib/docbuilder/src/docb_tr_cref2html.erl
new file mode 100644
index 0000000000..06748b8c57
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_cref2html.erl
@@ -0,0 +1,61 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_cref2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, {cref,_,[Header|Rest]}, _Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ {cref, Data, [{header,[],[]}|Rest]}.
+
+rule([header|_],_) ->
+ {drop, ""};
+
+rule([ret|_],_) ->
+ {"",""};
+
+rule([nametext|_],_) ->
+ {" ",""};
+
+rule([name|_], {_,_,[_Ret,{nametext,[],[{pcdata,[],Name}]}]}) ->
+ FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
+ TName = docb_util:trim(FName),
+ CAnchor = docb_util:fknidx(TName, "/"),
+ {"<A NAME=\"" ++ CAnchor ++ "\"><STRONG><CODE>",
+ "</CODE></STRONG></A><BR>\n"};
+rule([name|T], {I,As,[Ret,{pcdata,[],Name}]}) -> % For SGML DTD
+ rule([name|T], {I,As,[Ret,{nametext,[],[{pcdata,[],Name}]}]});
+
+rule([lib|_],_) ->
+ {"\n<H3>C LIBRARY</H3>\n<DIV CLASS=REFBODY>\n","\n</DIV>\n"};
+
+rule([libsummary|_],_) ->
+ {"\n<H3>C LIBRARY SUMMARY</H3>\n<DIV CLASS=REFBODY>\n","\n</DIV>\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html_ref:rule(TagHistory, TagBody).
+
+rule([cref|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:ref_top(Data, Opts),
+ docb_html_layout:ref_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_erlref2html.erl b/lib/docbuilder/src/docb_tr_erlref2html.erl
new file mode 100644
index 0000000000..b264c46bce
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_erlref2html.erl
@@ -0,0 +1,46 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_erlref2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, {erlref,_,[Header|Rest]}, _Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ {erlref, Data, [{header,[],[]}|Rest]}.
+
+rule([header|_],_) ->
+ {drop, ""};
+
+rule([module|_],_) ->
+ {"\n<h3>MODULE</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([modulesummary|_],_) ->
+ {"\n<h3>MODULE SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html_ref:rule(TagHistory, TagBody).
+
+rule([erlref|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:ref_top(Data, Opts),
+ docb_html_layout:ref_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_fileref2html.erl b/lib/docbuilder/src/docb_tr_fileref2html.erl
new file mode 100644
index 0000000000..60280543a8
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_fileref2html.erl
@@ -0,0 +1,46 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_fileref2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, {fileref,_,[Header|Rest]}, _Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ {fileref, Data, [{header,[],[]}|Rest]}.
+
+rule([header|_],_) ->
+ {drop, ""};
+
+rule([file|_],_) ->
+ {"\n<h3>FILE</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule([filesummary|_],_) ->
+ {"\n<h3>FILE SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
+
+rule(TagHistory, TagBody) ->
+ docb_html_ref:rule(TagHistory, TagBody).
+
+rule([fileref|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:ref_top(Data, Opts),
+ docb_html_layout:ref_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_first2html.erl b/lib/docbuilder/src/docb_tr_first2html.erl
new file mode 100644
index 0000000000..e9ecbe73cb
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_first2html.erl
@@ -0,0 +1,46 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_first2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, Tree, _Opts) ->
+ Tree.
+
+rule([header|_], _) ->
+ {drop, ""};
+
+rule([description|_], _) ->
+ {"", ""};
+
+rule([include|_], _) ->
+ {drop, ""};
+
+rule(TagHistory, TagBody) ->
+ docb_html:rule(TagHistory, TagBody).
+
+rule([first|_], {_,[],[Header|_]}, Opts) ->
+ HeaderData = docb_html_util:all_header_data(Header),
+ {{docb_html_layout:first_top(HeaderData, Opts),
+ docb_html_layout:first_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_index2html.erl b/lib/docbuilder/src/docb_tr_index2html.erl
new file mode 100644
index 0000000000..bbf419f3ef
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_index2html.erl
@@ -0,0 +1,197 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_index2html).
+
+-export([extension/0, transform/3, rule/2]).
+
+extension() ->
+ ".html".
+
+transform(_File0, {index, Attrs, [Header| Trees0]}, _Opts) ->
+ Trees1 = prune_flat(Trees0, false),
+ %%
+ %% Now each element of Trees1 is a tree with tag `name' and
+ %% attribute `File', and with one `pcdata' subtree containing the
+ %% name `Func' of the function. We extract `File' and `Func', and
+ %% create new trees.
+ %%
+ %% `File' is attribute CDATA (from an <include file=...>), and
+ %% `Func' is PCDATA.
+ %%
+ FileFuncs =
+ [{File, RefType, Func} ||
+ {name, [{_, _, File}, {_, _, RefType}|_],
+ [{pcdata, [], Func}]}
+ <- Trees1],
+ Trees2 = new_trees(FileFuncs),
+ {index, Attrs, [Header| Trees2]}.
+
+%% Remove all elements except those with tag equal to `name'.
+%% Within `name' remove all elements except those equal to `pcdata'.
+%% Add attribute `filetype' to `name'.
+%%
+%% Refs: appref, comref, cref, erlref, fileref
+prune_flat([{appref, _Attrs, More}| Rest], _) ->
+ RefType = appref,
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([{comref, _Attrs, More}| Rest], _) ->
+ RefType = comref,
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([{cref, _Attrs, More}| Rest], _) ->
+ RefType = cref,
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([{erlref, _Attrs, More}| Rest], _) ->
+ RefType = erlref,
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([{fileref, _Attrs, More}| Rest], _) ->
+ RefType = fileref,
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([{name, [Attr0|Attrs0], More}| Rest], RefType) ->
+ Attrs = [Attr0, {"FILETYPE", "CDATA", RefType} |
+ Attrs0],
+ [{name, Attrs, keep_pcdata(More)}| prune_flat(Rest, RefType)];
+prune_flat([{pcdata, _, _}| Rest], RefType) -> % special case
+ prune_flat(Rest, RefType);
+prune_flat([{_Tag, _Attrs, More}| Rest], RefType) ->
+ lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
+prune_flat([], _) ->
+ [].
+
+keep_pcdata(Trees) ->
+ lists:filter(fun({pcdata, _, _}) -> true;
+ (_) -> false
+ end, Trees).
+
+new_trees(FileFuncs) ->
+ Files0 = [{File, RefType} || {File, RefType, _} <- FileFuncs],
+ Files1 = lists:usort(Files0),
+ FileEntries = [{reffile, File, RefType,
+ [Fu || {Fi, _, Fu} <- FileFuncs, Fi == File]}
+ || {File, RefType} <- Files1],
+ FuncEntries = [{func, Func, RefType, [File]}
+ || {File, RefType, Func} <- FileFuncs],
+ Entries = FileEntries ++ FuncEntries,
+ SortedEntries = sort_entries(Entries),
+ %%
+ %% We create a tree according to the following "dtd":
+ %%
+ %% element index (reffile | funcdef)*
+ %% element reffile (funcdef2)*
+ %% attribute reffile filename CDATA
+ %% attribute reffile filetype CDATA
+ %% element funcdef2 PCDATA
+ %% attribute funcdef2 filename CDATA
+ %% attribute funcdef2 filetype CDATA
+ %% element funcdef PCDATA
+ %% attribute funcdef filename CDATA
+ %% attribute funcdef filetype CDATA
+ %%
+ %% For example:
+ %% <index>
+ %% <reffile filename="mymod" filetype="erlref">
+ %% <funcdef2 filename="mymod" filetype="erlref">myfunca(A)</>
+ %% <funcdef2 filename="mymod" filetype="erlref">myfuncb(A, B)</>
+ %% </>
+ %% <funcdef filename="mymod" filetype="erlref">myfunca(A)</>
+ %% <funcdef filename="mymod" filetype="erlref">myfuncb(A, B)</>
+ %% </>
+ lists:flatmap(
+ fun({reffile, File, RefType, Funcs}) ->
+ %% A reffile tree
+ [{reffile, [{"FILENAME", "CDATA", File},
+ {"FILETYPE", "CDATA", RefType}],
+ [{funcdef2, [{"FILENAME", "CDATA", File},
+ {"FILETYPE", "CDATA", RefType}],
+ [{pcdata, [], Func}]} || Func <- Funcs]}];
+ ({func, Func, RefType, [File]}) ->
+ %% A func tree
+ [{funcdef, [{"FILENAME", "CDATA", File},
+ {"FILETYPE", "CDATA", RefType}],
+ [{pcdata, [], Func}]}]
+ end, SortedEntries).
+
+%% Sorting of entries
+%%
+%% The sorting is based on how names of files and functions are
+%% presented (in a browser).
+%% Requires conversion to "function/2" etc.
+%%
+sort_entries(Entries) ->
+ ExpEntries =
+ lists:map(
+ fun({reffile, File, RefType, Funcs}) ->
+ HFile = filename_sort_order(File),
+ HFuncs = [{funcdef_sort_order(Fu, RefType), Fu} || Fu <- Funcs],
+ {reffile, HFile, File, RefType, lists:sort(HFuncs)};
+ ({func, Func, RefType, [File]}) ->
+ HFunc = funcdef_sort_order(Func, RefType),
+ HFile = filename_sort_order(File),
+ {func, HFunc, Func, RefType, [{HFile, File}]}
+ end, Entries),
+ SortedExpEntries = lists:keysort(2, ExpEntries),
+ lists:map(
+ fun({Tag, _HName, Name, RefType, Vals}) ->
+ NVals = lists:map(fun({_HVal, Val}) -> Val end, Vals),
+ {Tag, Name, RefType, NVals}
+ end, SortedExpEntries).
+
+rule([index| _], _) ->
+ {docb_html_layout:index_top("") ++
+ "<dl>\n",
+ "</dl>\n" ++ docb_html_layout:index_bot()};
+
+rule([header| _], _) ->
+ {drop, ""};
+
+rule([reffile| _], {_, [File, _RefType|_], _}) ->
+ CFile = docb_html_util:attribute_cdata_to_html(File),
+ {"<dt><em>" ++ CFile ++ "</em></dt>\n", ""};
+
+rule([funcdef2| _], {_, [File, RefType|_], [{pcdata, [], FuncDef}]}) ->
+ FFuncDef = lists:flatten(docb_html_util:pcdata_to_html(FuncDef)),
+ TFuncDef = docb_util:trim(FFuncDef),
+ ShortFuncDef = docb_html_util:make_funcdef_short(TFuncDef, RefType),
+ HRef =
+ docb_html_util:make_anchor_href_short(File, TFuncDef, RefType),
+ {drop,
+ "<dd><a href=\"" ++ HRef ++ "\"><code>" ++
+ ShortFuncDef ++ "</code></a></dd>\n"};
+
+rule([funcdef| _], {_, [File, RefType|_], [{pcdata, [], FuncDef}]}) ->
+ FFuncDef = lists:flatten(docb_html_util:pcdata_to_html(FuncDef)),
+ TFuncDef = docb_util:trim(FFuncDef),
+ ShortFuncDef = docb_html_util:make_funcdef_short(TFuncDef, RefType),
+ HRef =
+ docb_html_util:make_anchor_href_short(File, TFuncDef, RefType),
+ CFile = docb_html_util:attribute_cdata_to_html(File),
+ {drop,
+ "<dt><code>" ++ ShortFuncDef ++ "</code></dt>\n"
+ "<dd><a href=\"" ++ HRef ++ "\"><em>" ++
+ CFile ++ "</em></a></dd>\n"};
+
+rule(_, _) ->
+ {drop, ""}.
+
+filename_sort_order(File) ->
+ docb_html_util:html_latin1_sort_order(
+ lists:flatten(
+ docb_html_util:attribute_cdata_to_html(string:strip(File)))).
+
+funcdef_sort_order(FuncDef, RefType) ->
+ docb_html_util:html_latin1_sort_order(
+ docb_html_util:make_anchor_name_short(FuncDef, RefType)).
diff --git a/lib/docbuilder/src/docb_tr_part2html.erl b/lib/docbuilder/src/docb_tr_part2html.erl
new file mode 100644
index 0000000000..dd44c4a8df
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_part2html.erl
@@ -0,0 +1,240 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_part2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(File, {part, _Attrs, [Header| Rest]}, Opts0) ->
+
+ %% Extract header data
+ Title = docb_html_util:extract_header_data(title, Header),
+
+ %% Create the framing HTML document
+ OutFile = docb_util:outfile(File ++ "_frame", ".html", Opts0),
+ case file:open(OutFile, [write]) of
+ {ok, Frame} ->
+ io:format(Frame,
+"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
+<!-- This document was generated using DocBuilder-" ++ docb_util:version() ++ " -->
+<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
+<head>
+ <title>~s</title>
+ " ++ docb_util:html_snippet(head, Opts0) ++ "
+</head>
+<frameset cols=\"200, *\">
+ <frame src=\"~s\" name=\"toc\"/>
+ <frame src=\"~s\" name=\"document\"/>
+ <noframes>
+ <body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\"
+ vlink=\"#FF00FF\" alink=\"#FF0000\">
+ <p>This documentation requires a browser that can handle frames</p>
+ </body>
+ </noframes>
+</frameset>
+</html>
+",
+ [Title, File ++ ".html", File ++ "_first.html"]),
+ file:close(Frame)
+ end,
+
+ %% Create the front HTML document
+ docb_main:transform(first, html, Opts0, File ++ "_first",
+ {first, [], [Header| Rest]}),
+
+ %% Extract files to include
+ Files =
+ case Rest of
+ [{description, _, _}| NewRest] ->
+ lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end,
+ NewRest);
+ [{include, _, _}| _NewRest] ->
+ lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end, Rest)
+ end,
+
+ %% Concat all chapters into a *big* parse tree
+ %% Also transform them to HTML
+ TransformP = not docb_util:an_option(framework_only, Opts0),
+ TOpts = [dict, {part_application,File}],
+ ConcatTree = concat_files(Files, Opts0, TransformP, TOpts),
+
+ %% Create a cites dictionary
+ docb_main:transform(cite, html, Opts0, File ++ "_cite",
+ {cite, [], [Header| ConcatTree]}),
+
+ %% Create a terms dictionary
+ docb_main:transform(term, html, Opts0, File ++ "_term",
+ {term, [], [Header| ConcatTree]}),
+
+ %% Find all fascicules to be put in the top menu of the table of
+ %% contents
+ Ext = docb_util:lookup_option(src_type, Opts0),
+ Opts2 =
+ case filelib:is_regular("fascicules"++Ext) of
+ true ->
+ case docb_main:parse1("fascicules", Opts0) of
+ {ok, Parse} ->
+ FascData = get_fasc_data(Parse),
+ case lists:keysearch(File, 1, FascData) of
+ {value, {_, _, "YES", _}} ->
+ OrigFile =
+ docb_util:outfile(File++"_frame",
+ ".html", Opts0),
+ EntryFile =
+ docb_util:outfile("index",
+ ".html", Opts0),
+ docb_util:message(info,
+ "Copying ~s to ~s",
+ [OrigFile,EntryFile]),
+ file:copy(OrigFile, EntryFile);
+ _ ->
+ ok
+ end,
+ [{fascdata, FascData}| Opts0];
+ errors ->
+ %% do not bother
+ docb_util:message(
+ warning,
+ "fascicules~s could not be parsed,"
+ " no index.html created~n", [Ext]),
+ Opts0
+ end;
+ _ ->
+ %% do not bother
+ docb_util:message(warning,
+ "fascicules~s not found, "
+ "no index.html created~n",
+ [Ext]),
+ Opts0
+ end,
+
+ %% Create ToC parse tree
+ {{toc, [{"FILE", "CDATA", File}], [Header| ConcatTree]}, Opts2}.
+
+concat_files(Files, Opts, TransformP, TOpts) ->
+ Ext = docb_util:lookup_option(src_type, Opts),
+ concat_files(Files, [], 1, Opts, TransformP, TOpts, Ext).
+
+concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
+ case docb_main:parse1(File, Opts) of
+ {ok, Parse} ->
+ {TopTag, Attrs, [Header = {header, _, HeaderContents} | More]} = Parse,
+ {value,{title,_,Title}} = lists:keysearch(title,1,HeaderContents),
+ NewMore = [{section, [], [{title, [], Title}| More]}],
+ NewParse = {TopTag, Attrs, [Header| NewMore]},
+ if
+ TP ->
+ docb_util:message(info,
+ "Processing \"~s~s\"",
+ [File, Ext]),
+ Opts2 =
+ [html, {number,integer_to_list(ChLevel)}] ++
+ TOpts ++ Opts,
+ docb_main:transform(TopTag, html, Opts2, File,
+ NewParse);
+ true -> ignore
+ end,
+ NumberTree =
+ docb_html_util:number(NewParse,
+ integer_to_list(ChLevel), File),
+ {_, [], [_| NewBody]} = NumberTree,
+ lists:append(Body,
+ concat_files(Rest, NewBody, ChLevel+1, Opts,
+ TP, TOpts, Ext));
+ errors ->
+ throw({error,"Parse error when building chapter "++File})
+ end;
+concat_files([], Body, _ChLevel, _Opts, _TP, _TOpts, _Ext) ->
+ Body.
+
+rule([section| _], _) ->
+ {"", ""};
+
+rule(_, _) ->
+ {drop, ""}.
+
+rule([toc| _], {_Depth, [File], [Header| _]}, Opts) ->
+ case docb_util:lookup_option(fascdata, Opts) of
+ false ->
+ {{docb_html_layout:part_toc_top(
+ docb_html_util:all_header_data(Header), File, Opts),
+ docb_html_layout:part_toc_bot()}, Opts};
+ FascData ->
+ HRefTexts =
+ lists:map(
+ fun({_File, HRef, _Entry, PCText}) ->
+ {HRef, docb_html_util:pcdata_to_html(PCText)}
+ end,
+ FascData),
+ {{docb_html_layout:part_toc_top(
+ docb_html_util:all_header_data(Header),
+ File, Opts, HRefTexts),
+ docb_html_layout:part_toc_bot()}, Opts}
+ end;
+
+rule([title| Rest], {_, [Number, File], [{pcdata, _, Title}]}, Opts) ->
+ N = docb_html_util:count_sections(Rest),
+ OutFile = docb_html_util:make_anchor_href(File),
+ if
+ N == 1 ->
+ {{drop,
+ "<hr/>\n<small>" ++
+ Number ++
+ " <a target=\"document\" href=\"" ++ OutFile ++ "#" ++
+ Number ++ "\">" ++
+ docb_html_util:pcdata_to_html(Title) ++
+ "</a></small><br/>\n"},
+ Opts};
+ N < 3 ->
+ {{drop,
+ "<small>" ++
+ Number ++
+ " <a target=\"document\" href=\"" ++ OutFile ++ "#" ++
+ Number ++ "\">" ++
+ docb_html_util:pcdata_to_html(Title) ++
+ "</a></small><br/>\n"},
+ Opts};
+ true ->
+ {{drop, ""}, Opts}
+ end.
+
+%% Parsed fascicules:
+%% {fascicules,[],
+%% [{fascicule, [{"FILE","CDATA","refman"},
+%% {"HREF","CDATA","refman_frame.html"},
+%% {"ENTRY","TOKEN","YES"}],
+%% [{pcdata, [], "" Reference Manual\\n \n"}]},
+%% Returns: [{File, HRef, Entry, Text}].
+get_fasc_data({fascicules, _, Fascs}) ->
+ lists:map(
+ fun({fascicule, Atts, Trees}) ->
+ AVals = get_avals(Atts),
+ PCText = get_pc_text(Trees),
+ list_to_tuple(lists:append([AVals, [PCText]])) end,
+ Fascs).
+
+get_avals(Atts) ->
+ lists:map(fun(Tuple) ->
+ element(3, Tuple) end,
+ Atts).
+
+get_pc_text([{pcdata, _, Text}]) ->
+ Text.
diff --git a/lib/docbuilder/src/docb_tr_refs2kwic.erl b/lib/docbuilder/src/docb_tr_refs2kwic.erl
new file mode 100644
index 0000000000..dc60c329fc
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_refs2kwic.erl
@@ -0,0 +1,156 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_refs2kwic).
+
+-export([extension/0, transform/3, rule/2]).
+
+%% Output parts of a parsetree that contains a series of reference
+%% manual pages. The tags considered are: module, file, app, com and lib
+%% (and their corresponding *summary tags), and name, fsummary, c, em,
+%% ret and pcdata.
+
+extension() ->
+ ".kwc".
+
+transform(File, Tree, Opts) ->
+ {refs, [], Trees} = Tree,
+ FileTree = {srcfile, [], [{pcdata, [], File}]},
+ AppName = docb_util:lookup_option(name, Opts, "unknown"),
+ AppTree = {appname, [], [{pcdata, [], AppName}]},
+ Vsn = docb_util:lookup_option(vsn, Opts, "unknown"),
+ VsnTree = {appvsn, [], [{pcdata, [], Vsn}]},
+ NewTree = {refs, [], [FileTree, AppTree, VsnTree| Trees]},
+ {NewTree, Opts}.
+
+rule([refs|_],_) ->
+ {"%% Automatically generated. Do not edit.\n", ""};
+
+rule([srcfile| _], _) ->
+ {"{srcfile, \"", "\"}.\n"};
+
+rule([appname| _], _) ->
+ {"{appname, \"", "\"}.\n"};
+
+rule([appvsn| _], _) ->
+ {"{appvsn, \"", "\"}.\n"};
+
+rule([erlref|_ ], _) ->
+ {"", ""};
+
+rule([fileref|_ ], _) ->
+ {"", ""};
+
+rule([appref|_ ], _) ->
+ {"", ""};
+
+rule([comref|_ ], _) ->
+ {"", ""};
+
+rule([cref|_ ], _) ->
+ {"", ""};
+
+rule([module| _], {_, [File], _}) ->
+ {drop, "{module, \"" ++ File ++ "\"}.\n"};
+
+rule([file|_], {_, [File], _}) ->
+ {drop, "{file, \"" ++ File ++ "\"}.\n"};
+
+rule([app|_], {_, [File], _}) ->
+ {drop, "{app, \"" ++ File ++ "\"}.\n"};
+
+rule([com|_], {_, [File], _}) ->
+ {drop, "{com, \"" ++ File ++ "\"}.\n"};
+
+rule([lib|_], {_, [File], _}) ->
+ {drop, "{lib, \"" ++ File ++ "\"}.\n"};
+
+rule([modulesummary|_], _) ->
+ {"{modulesummary, \"", "\"}.\n"};
+
+rule([filesummary|_], _) ->
+ {"{filesummary, \"", "\"}.\n"};
+
+rule([appsummary|_], _) ->
+ {"{appsummary, \"", "\"}.\n"};
+
+rule([comsummary|_], _) ->
+ {"{comsummary, \"", "\"}.\n"};
+
+rule([libsummary|_], _) ->
+ {"{libsummary, \"", "\"}.\n"};
+
+rule([funcs|_ ], _) ->
+ {"", ""};
+
+rule([func|_ ], _) ->
+ {"", ""};
+
+rule([name,func,funcs,cref|_], {_,[_File], [_Ret,{pcdata,[],Name}]}) ->
+ FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
+ TName = docb_util:trim(FName),
+ case catch docb_util:fknidx(TName, "/") of
+ {'EXIT',_} ->
+ {drop, ["{name, \"", escq(TName), "\"}.\n"]};
+ FuncName ->
+ {drop, ["{name, \"", escq(FuncName), "\"}.\n"]}
+ end;
+
+rule([name,func,funcs,erlref|_], {_,[_File], [{pcdata,[],Name}]}) ->
+ FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
+ TName = docb_util:trim(FName),
+ case catch docb_util:fknidx(TName, "/") of
+ {'EXIT',_} ->
+ {drop, ["{name, \"", escq(TName), "\"}.\n"]};
+ FuncName ->
+ {drop, ["{name, \"", escq(FuncName), "\"}.\n"]}
+ end;
+
+rule([name, func| _], {_, [_File], [{pcdata, [], Name}]}) ->
+ FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
+ TName = docb_util:trim(FName),
+ Cmd = case string:tokens(TName, " ") of
+ [Cmd0| _] ->
+ Cmd0;
+ _ ->
+ TName
+ end,
+ {drop, ["{name, \"", escq(Cmd), "\"}.\n"]};
+
+rule([fsummary| _], _) ->
+ {"{fsummary, \"", "\"}.\n"};
+
+rule([c, fsummary|_], _) ->
+ {"", ""};
+
+rule([em, fsummary|_], _) ->
+ {"", ""};
+
+rule([pcdata| _], {_, _, Data}) ->
+ FData = lists:flatten(docb_html_util:pcdata_to_html(Data)),
+ Out = lists:map(fun($\n) -> $ ; (C) -> C end, FData),
+ {drop, escq(Out)};
+
+rule(_, _) ->
+ {drop, ""}.
+
+escq(Cs) ->
+ lists:flatmap(fun($") ->
+ "\\\"";
+ (C) -> [C]
+ end,
+ Cs).
diff --git a/lib/docbuilder/src/docb_tr_report2html.erl b/lib/docbuilder/src/docb_tr_report2html.erl
new file mode 100644
index 0000000000..3386ed972a
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_report2html.erl
@@ -0,0 +1,70 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_report2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+%%
+%% File extension
+%%
+
+extension() ->
+ ".html".
+
+transform(File, {report,_,[Header|Rest]}, Opts) ->
+ Data = [{[], [], docb_html_util:all_header_data(Header)}],
+ Tree = {report, Data, [{header,[],[]}|Rest]},
+ ChapterLevel = case docb_util:lookup_option(number, Opts) of
+ false -> none;
+ Value -> Value
+ end,
+ NumberTree = docb_html_util:number(Tree, ChapterLevel, File),
+ options(NumberTree, Opts).
+
+options(Tree, []) ->
+ Tree;
+options(Tree, [_|Rest]) ->
+ options(Tree, Rest).
+
+rule([header|_], _) ->
+ {drop, ""};
+
+rule([toc|_], {_,_,ToC}) ->
+ {drop, "\n<h3>Table of Contents</h3>\n" ++
+ docb_html_util:format_toc(ToC) ++ "\n"};
+
+rule([section|_], _) ->
+ {"", ""};
+
+rule([title|Rest], {_,[Number,_File], [{pcdata,_,Title}]}) ->
+ N = integer_to_list(docb_html_util:count_sections(Rest)+1),
+ {drop, "\n<h" ++ N ++ ">" ++ Number ++ " " ++
+ docb_html_util:pcdata_to_html(Title) ++ "</h" ++ N ++ ">\n"};
+
+rule([erlinclude|_], {_,[File,Tag],_}) ->
+ docb_html_util:erl_include(File, Tag);
+
+rule(TagHistory, TagBody) ->
+ docb_html:rule(TagHistory, TagBody).
+
+rule([report|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:report_top(Data, Opts),
+ docb_html_layout:report_bot(Opts)}, Opts};
+
+rule(TagHistory, TagBody, Opts) ->
+ docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_term2html.erl b/lib/docbuilder/src/docb_tr_term2html.erl
new file mode 100644
index 0000000000..0a993cebb1
--- /dev/null
+++ b/lib/docbuilder/src/docb_tr_term2html.erl
@@ -0,0 +1,126 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_tr_term2html).
+
+-export([extension/0, transform/3, rule/2, rule/3]).
+
+extension() ->
+ ".html".
+
+transform(_File, Tree, Opts) ->
+ purge(Tree, Opts).
+
+purge({Tag, Attrs, [Header|Body]}, Opts) ->
+ TermList = case docb_util:lookup_option({defs,term}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ B1 = purge_body(Body, TermList),
+ B2 = lists:ukeysort(2, B1),
+ {Tag, Attrs, [Header|B2]}.
+
+purge_body([], _) ->
+ [];
+purge_body([{pcdata,_Attrs,_More}|Rest], TermList) ->
+ purge_body(Rest, TermList);
+purge_body([{term,[{"ID","CDATA",ID}],More}|Rest], TermList) ->
+ case lists:keysearch(ID, 1, TermList) of
+ false ->
+ [{term,[{"NAME","CDATA",ID},{"ID","CDATA",ID}],More}|
+ purge_body(Rest, TermList)];
+ {value, {ID, Name, _Description, _Responsible}} ->
+ [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
+ purge_body(Rest, TermList)];
+ {value, {ID, Name, _Description}} ->
+ [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
+ purge_body(Rest, TermList)]
+ end;
+purge_body([{_Tag,_Attrs,More}|Rest], TermList) ->
+ lists:append(purge_body(More, TermList),
+ purge_body(Rest, TermList)).
+
+rule([header|_], _) ->
+ {drop, ""};
+
+rule(_, _) ->
+ {drop, ""}.
+
+rule([term|_], {_,[],[Header]}, Opts) ->
+ {{docb_html_layout:chapter_top(
+ docb_html_util:all_header_data(Header), Opts) ++
+ "\n<center><h1>Glossary</h1></center>\n",
+ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([term|_], {_,[],[Header|_]},Opts) ->
+ {{docb_html_layout:chapter_top(
+ docb_html_util:all_header_data(Header), Opts) ++
+ "\n<center><h1>Glossary</h1></center>\n<dl>\n",
+ "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([term|_], {_,[Data],_}, Opts) ->
+ {{docb_html_layout:chapter_top(Data, Opts) ++
+ "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
+ "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
+
+rule([term|_], {_,[Name,ID],[{termdef,[],[{pcdata,[],Def}]}]}, Opts) ->
+ TermList = case docb_util:lookup_option({defs,term}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ case lists:keysearch(ID, 1, TermList) of
+ false ->
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ ID ++ "</strong></a>\n</dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
+ {value, {ID, Name, Description, _Responsible}} ->
+ docb_util:message(warning,
+ "Global term ~s overriding local", [ID]),
+ {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
+ Opts};
+ {value, {ID, Name, Description}} ->
+ docb_util:message(warning,
+ "Global term ~s overriding local", [ID]),
+ {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
+ end;
+
+rule([term|_], {_,[Name,ID],_}, Opts) ->
+ TermList = case docb_util:lookup_option({defs,term}, Opts) of
+ false -> [];
+ Value -> Value
+ end,
+ case lists:keysearch(ID, 1, TermList) of
+ false ->
+ docb_util:message(error,
+ "The term ~s has no definition", [ID]),
+ {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
+ "??" ++ "\n</dd>\n"}, Opts};
+ {value, {ID, Name, Description, _Responsible}} ->
+ {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
+ Opts};
+ {value, {ID, Name, Description}} ->
+ {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
+ "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
+ docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
+ end.
diff --git a/lib/docbuilder/src/docb_transform.erl b/lib/docbuilder/src/docb_transform.erl
new file mode 100644
index 0000000000..a432038adf
--- /dev/null
+++ b/lib/docbuilder/src/docb_transform.erl
@@ -0,0 +1,161 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_transform).
+
+-export([file/1, file/2]).
+
+%% file(File) -> ok | {error, Reason}
+%% file(File, Opts) -> ok | {error, Reason}
+%% File = string(), file name with or without ".xml" extension
+%% Opts = [Opt]
+%% Reason = badfile | {badopt, Term}
+file(File0) ->
+ file(File0, []).
+file(File0, RawOpts) ->
+ File = filename:rootname(File0), % without extension
+ Ext = case filename:extension(File0) of
+ ".xml" -> ".xml";
+ ".sgml" -> ".sgml";
+ "" ->
+ %% If the file is given without extension, we try to
+ %% infer if the source file is XML or SGML.
+ %% SGML is supported *internally within OTP* for
+ %% backwards compatibility reasons.
+ case filelib:is_regular(File++".xml") of
+ true -> ".xml";
+ false -> ".sgml"
+ end;
+ _Ext0 -> % this is probably an error...
+ ".xml"
+ end,
+ case filelib:is_regular(File++Ext) of
+ true ->
+ case parse(RawOpts) of
+ {ok, Opts0} ->
+ {ok, Cwd} = file:get_cwd(),
+ Opts = [{src_type,Ext},
+ {src_dir,Cwd},
+ {src_file,File},
+ {{local_defs,term},[]},
+ {{local_defs,cite},[]} | Opts0],
+ case docb_main:process(File, Opts) of
+ errors -> error;
+ ok -> ok
+ end;
+ Error -> % {error, {badopt,Term}}
+ Error
+ end;
+ false ->
+ {error, badfile}
+ end.
+
+parse(RawOpts) ->
+ parse(RawOpts, []).
+
+%% Officially supported options
+
+parse([{html_mod,Module} | RawOpts], Opts) when is_atom(Module) ->
+ parse(RawOpts, [{html_mod,Module} | Opts]);
+parse([{outdir,Dir} | RawOpts], Opts) when is_list(Dir) ->
+ parse(RawOpts, [{outdir,Dir} | Opts]);
+parse([{number,N} | RawOpts], Opts) when is_integer(N) ->
+ parse(RawOpts, [{number,integer_to_list(N)} | Opts]);
+parse([{number,Nstr} | RawOpts], Opts) -> % list when called from script
+ parse(RawOpts, [{number,Nstr} | Opts]);
+parse([{ptype,Type} | RawOpts], Opts) when Type==unix;
+ Type==windows ->
+ parse(RawOpts, [{ptype,atom_to_list(Type)} | Opts]);
+parse([{ptype,Type} | RawOpts], Opts) -> % list when called from script
+ parse(RawOpts, [{ptype,Type} | Opts]);
+parse([silent | RawOpts], Opts) ->
+ put(option_silent, true),
+ parse(RawOpts, [silent | Opts]);
+parse([{top,Index} | RawOpts], Opts) when is_list(Index) ->
+ parse(RawOpts, [{top,Index} | Opts]);
+parse([{vsn,Vsn} | RawOpts], Opts) when is_list(Vsn) ->
+ parse(RawOpts, [{vsn,Vsn} | Opts]);
+
+parse([{term_defs,File} | RawOpts], Opts) when is_list(File) ->
+ Opts2 = get_defs(term, File, Opts),
+ parse(RawOpts, Opts2);
+parse([{cite_defs,File} | RawOpts], Opts) when is_list(File) ->
+ Opts2 = get_defs(cite, File, Opts),
+ parse(RawOpts, Opts2);
+
+%% OTP internal options (SGML and PDF support etc.)
+
+parse([html | RawOpts], Opts) ->
+ parse(RawOpts, [html | Opts]);
+parse([latex | RawOpts], Opts) ->
+ parse(RawOpts, [latex | Opts]);
+parse([{man,Level} | RawOpts], Opts) -> % Level = 1..9
+ parse(RawOpts, [{man,Level} | Opts]);
+
+parse([{booksty,StyFile} | RawOpts], Opts) -> % "otpA4" | "otpBOOK"
+ parse(RawOpts, [{booksty,StyFile} | Opts]);
+parse([{includepath,Dir} | RawOpts], Opts) ->
+ parse(RawOpts, [{includepath,Dir} | Opts]);
+parse([showpaths | RawOpts], Opts) ->
+ parse(RawOpts, [showpaths | Opts]);
+parse([straight | RawOpts], Opts) ->
+ parse(RawOpts, [straight | Opts]);
+parse([{ent,Ent} | RawOpts], Opts) ->
+ parse(RawOpts, [{ent,Ent} | Opts]);
+
+%% Undocumented options
+
+parse([{name, Name} | RawOpts], Opts) ->
+ parse(RawOpts, [{name, Name} | Opts]);
+parse([framework_only | RawOpts], Opts) ->
+ parse(RawOpts, [framework_only | Opts]);
+parse([kwicindex_only | RawOpts], Opts) ->
+ parse(RawOpts, [kwicindex_only | Opts]);
+
+parse([], Opts) ->
+ {ok, Opts};
+parse([Opt | _RawOpts], _Opts) ->
+ {error, {badopt, Opt}}.
+
+%% Type = term | cite
+get_defs(Type, File, Opts) ->
+ Key = {defs,Type},
+ {PrevDefs, Opts2} =
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {_, Defs0}} ->
+ {Defs0, lists:keydelete(Key, 1, Opts)};
+ false ->
+ {[], Opts}
+ end,
+ NewDefs = case file:consult(File) of
+ {ok, [DefL]} when is_list(DefL) ->
+ DefL;
+ {ok, _Terms} ->
+ docb_util:message(error,
+ "Skipping defs file ~s, does "
+ "not contain one list", [File]),
+ [];
+ {error, Error} ->
+ Expl = lists:flatten(file:format_error(Error)),
+ docb_util:message(error,
+ "Skipping defs file ~s, ~s",
+ [File, Expl]),
+ []
+ end,
+ [{Key,PrevDefs++NewDefs} | Opts2].
+
+
diff --git a/lib/docbuilder/src/docb_util.erl b/lib/docbuilder/src/docb_util.erl
new file mode 100644
index 0000000000..59673ef3a4
--- /dev/null
+++ b/lib/docbuilder/src/docb_util.erl
@@ -0,0 +1,237 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_util).
+
+-export([version/0, old_docb_dir/0, dtd_dir/0]).
+-export([html_snippet/2, html_snippet/3]).
+-export([lookup_option/2, lookup_option/3, lookup_options/2,
+ an_option/2]).
+-export([outfile/3, full_file_name/4]).
+-export([message/2, message/3]).
+-export([ltrim/1, rtrim/1, trim/1]).
+-export([join/2]).
+-export([fknidx/2]).
+
+-include("docb_util.hrl").
+
+%%--DocBuilder info-----------------------------------------------------
+
+%% version() -> string()
+%% Returns the DocBuilder application version.
+version() ->
+ DocbDir = code:lib_dir(docbuilder),
+ case string:tokens(filename:basename(DocbDir), "-") of
+ [_, Vsn] -> Vsn;
+ _ -> "unknown"
+ end.
+
+%% old_docb_dir() -> string()
+%% Returns the root directory of Old_DocBuilder (OTP internal).
+old_docb_dir() ->
+ "/home/otp/sgml/docb".
+
+%% dtd_dir() -> string()
+%% Returns the directory where the XML DTDs are located.
+dtd_dir() ->
+ DocbDir = code:lib_dir(docbuilder),
+ filename:join(DocbDir, "dtd").
+
+%%--User defined HTML snippets------------------------------------------
+
+%% html_snippet(What, Opts) -> HTML
+%% html_snippet(What, Arg, Opts) -> HTML
+%% What = head | seealso
+%% HTML = string()
+html_snippet(What, Opts) ->
+ case lookup_option(html_mod, Opts) of
+ false -> "";
+ Module ->
+ case catch apply(Module, What, []) of
+ HTML when is_list(HTML) ->
+ HTML;
+ {'EXIT', {undef, _}} ->
+ "";
+ {'EXIT', Reason} ->
+ message(warning,
+ "Callback function ~p:~p() => ~p",
+ [Module, What, Reason]),
+ "";
+ Other ->
+ message(warning,
+ "Callback function ~p:~p() => ~p",
+ [Module, What, Other]),
+ ""
+ end
+ end.
+html_snippet(What, Arg, Opts) ->
+ case lookup_option(html_mod, Opts) of
+ false -> "";
+ Module ->
+ case catch apply(Module, What, [Arg]) of
+ HTML when is_list(HTML) ->
+ HTML;
+ {'EXIT', {undef, _}} ->
+ "";
+ {'EXIT', Reason} ->
+ message(warning,
+ "Callback function ~p:~p(~p) => ~p",
+ [Module, What, Arg, Reason]),
+ "";
+ Other ->
+ message(warning,
+ "Callback function ~p:~p(~p) => ~p",
+ [Module, What, Arg, Other]),
+ ""
+ end
+ end.
+
+%%--Option utilities----------------------------------------------------
+
+%% Opts = [{Opt,Value} | Opt]
+
+%% lookup_option(Opt, Opts) -> Value | false
+lookup_option(Opt, Opts) ->
+ case lists:keysearch(Opt, 1, Opts) of
+ {value, {Opt,Value}} -> Value;
+ false -> false
+ end.
+
+%% lookup_option(Opt, Opts, DefaultValue) -> Value | DefaultValue
+lookup_option(Opt, Opts, DefaultValue) ->
+ case lookup_option(Opt,Opts) of
+ false -> DefaultValue;
+ Value -> Value
+ end.
+
+%% lookup_options(Opt, Opts) -> [Value]
+%% Used when the same option can be defined several times and returns
+%% the (possibly empty) list of values.
+lookup_options(Opt, Opts) ->
+ [V || {O, V} <- Opts, O == Opt].
+
+%% an_option(Opt, Opts) -> bool()
+an_option(Opt, Opts) ->
+ lists:member(Opt, Opts).
+
+%%--File handling-------------------------------------------------------
+
+%% outfile(File0, Extension, Opts) -> File
+%% Build the full filename for where to place a resulting file.
+outfile(File0, Extension, Opts) ->
+ File =
+ case regexp:match(File0, "[^/]*\$") of
+ {match,Start,Length} ->
+ string:substr(File0, Start, Length);
+ _ ->
+ File0
+ end,
+ full_file_name(File, Extension, outdir, Opts).
+
+%% full_file_name(File, Extension, What, Opts) -> File'
+%% File = string()
+%% What = outdir | includepath
+%% Prepend the full path name.
+full_file_name(File, Extension, What, Opts) ->
+ Path = lookup_option(What, Opts, ""),
+ full_file_name(File, Extension, Path).
+
+full_file_name(File0, Extension, Path) ->
+ File = case filename:extension(File0) of
+ Extension -> File0;
+ _ -> File0++Extension
+ end,
+
+ case File of
+ [$/|_] -> File;
+ [$~|_] -> File;
+ _ when Path=/="" -> filename:join(Path, File);
+ _ -> File
+ end.
+
+%%--Messages to the user------------------------------------------------
+
+%% message(Class, Format)
+%% message(Class, Format, Values) -> ok
+%% Class = info | warning | error
+%% Format, Values -- as in io:format/2
+%% Prints a warning or error message.
+%% Call as util:message(warning, "~w is undefined", [foo]).
+message(Class, Format) ->
+ message(Class, Format, []).
+message(Class, Format, Values) ->
+ Prefix = case Class of
+ info -> "";
+ warning -> "*** Warning: ";
+ error -> "*** Error: "
+ end,
+ case get(option_silent) of
+ true when Class==warning ->
+ ok;
+ _ ->
+ io:format(Prefix, []),
+ io:format(Format, Values),
+ io:nl()
+ end.
+
+%%--String handling-----------------------------------------------------
+
+%% ltrim(Str) -> Str'
+%% rtrim(Str) -> Str'
+%% trim(Str) -> Str'
+%% Strips whitespace from left, right or both.
+ltrim(Str) ->
+ lists:dropwhile(fun white_space/1, Str).
+rtrim(Str) ->
+ lists:reverse(ltrim(lists:reverse(Str))).
+trim(Str) ->
+ rtrim(ltrim(Str)).
+
+white_space($ ) -> true;
+white_space(C) when C<$ -> true;
+white_space($\n) -> true;
+white_space($\t) -> true;
+white_space(_) -> false.
+
+%% join(Strings, With) -> string()
+join([H1, H2| T], S) ->
+ H1 ++ S ++ join([H2| T], S);
+join([H], _) ->
+ H;
+join([], _) ->
+ [].
+
+%%--Other---------------------------------------------------------------
+
+%% fknidx(FNdef0, Fn_arity_sep) -> string()
+%% Get me the function name and arity.
+fknidx(FNdef0, Fn_arity_sep) ->
+ FNdef = string:strip(FNdef0),
+ case string:tokens(FNdef,"(") of
+ [FNdef] ->
+ %% No parentheses, assume variable: remove nl:s at end,
+ %% and strip blanks.
+ string:strip(string:strip(FNdef, right, $\n));
+ [Name0|Args0] ->
+ [Args1|_] = string:tokens(string:strip(hd(Args0)), "-"),
+ Arity = case Args1 of
+ [$)|_] -> 0;
+ _ ->
+ length(string:tokens(Args1, ","))
+ end,
+ string:strip(Name0)++Fn_arity_sep++integer_to_list(Arity)
+ end.
diff --git a/lib/docbuilder/src/docb_util.hrl b/lib/docbuilder/src/docb_util.hrl
new file mode 100644
index 0000000000..01ef3f7fca
--- /dev/null
+++ b/lib/docbuilder/src/docb_util.hrl
@@ -0,0 +1,34 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+
+%%% For character conversion
+
+-record(in_opts, {expand_entities=false,
+ encode_filter = fun(X) -> X end}).
+-record(out_opts, {escape_chars=false,
+ remove_nl=false,
+ delete_trailing_whitespace=false,
+ delete_trailing_nl=false,
+ compress_white_space=false,
+ escape_filter = fun(X) -> X end}).
+
+
+-define(pcdata_IN, #in_opts{expand_entities=true}).
+-define(rcdata_IN, #in_opts{expand_entities=true}).
+-define(cdata_IN, #in_opts{}).
+
diff --git a/lib/docbuilder/src/docb_xmerl_tree_cb.erl b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
new file mode 100644
index 0000000000..d57f55bff8
--- /dev/null
+++ b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
@@ -0,0 +1,343 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the Licence for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
+%% All Rights Reserved.��
+%%
+%% $Id$
+%%
+-module(docb_xmerl_tree_cb).
+
+%% This is the XMerL callback module for exporting XML to the internal
+%% tree format used by DocBuilder.
+%% {Doc, _Misc} = xmerl_scan:file("file.xml", [{validation,true}])
+%% Tree = xmerl:export([Doc], docb_xmerl_tree_cb)
+
+-export(['#xml-inheritance#'/0]).
+
+-export(['#root#'/4,
+ '#text#'/1,
+ '#element#'/5]).
+-include("xmerl.hrl").
+
+%%--Functions used by xmerl---------------------------------------------
+
+'#xml-inheritance#'() ->
+ [].
+
+'#root#'(Data, _Attrs, [], _E) ->
+ Data.
+
+'#text#'(Text) ->
+ Text2 = strip_leading_blanks(Text),
+%% before
+%% case Text2 of
+%% [$\n|T] ->
+%% case is_empty(T) of
+%% true -> [];
+%% false -> {pcdata, [], nl(Text2)}
+%% end;
+%%
+%% _ ->
+%% {pcdata, [], nl(Text2)}
+%% end.
+%% after
+ {pcdata, [], nl(Text2)}.
+
+'#element#'(Tag, Data, Attrs, Parents, _E) when Tag==pre; Tag==code ->
+ [H|T] = reinsert_nl(Data),
+ NewData = [strip_nl(H)|T],
+ NewData2 = case Tag of
+ code ->
+ fix_single_pcdata(NewData);
+ pre ->
+ NewData
+ end,
+ {Tag, attrs(get_dtd(Parents), Tag, Attrs), NewData2};
+'#element#'(Tag, Data, Attrs, Parents, _E) ->
+ NewData = case tag_content(Tag) of
+ no_pcdata -> % remove all pcdata
+ [Dat||
+ Dat <- Data,
+ begin
+ Fun = fun({pcdata,_,_}) -> false;
+ (_) -> true end,
+ Fun(Dat)
+ end];
+ single_pcdata when length(Data)>1 ->
+ %% merge several pcdata's into one single pcdata
+ fix_single_pcdata(Data);
+ _ ->
+ lists:flatten(Data)
+ end,
+ {Tag, attrs(get_dtd(Parents), Tag, Attrs), NewData}.
+
+%%--Internal functions--------------------------------------------------
+
+%% is_empty(Str) -> bool()
+%% Returns true if the string Str only contains blanks, tabs and
+%% newlines, false otherwise.
+%% is_empty("\n" ++ Text) ->
+%% is_empty(Text);
+%% is_empty("\t" ++ Text) ->
+%% is_empty(Text);
+%% is_empty(" " ++ Text) ->
+%% is_empty(Text);
+%% is_empty("") ->
+%% true;
+%% is_empty(_) ->
+%% false.
+
+%% reinsert_nl(L1) -> L2
+%% Workaround for <pre>: Normally empty lines are ignored. However,
+%% Xmerl splits lines whenever it encounters an entity. In the case of
+%% <pre>, this may lead to that we ignores what we think is an empty
+%% line but is actually a line break that should be kept, for example
+%% in this case:
+%% <pre>
+%% <input>some command</input> <-- this line break is lost!
+%% &lt;some result&gt;
+%% </pre>
+%% This function reinserts line breaks where necessary.
+reinsert_nl([[]|T]) ->
+ [{pcdata,[],"\\n"} | reinsert_nl(T)];
+reinsert_nl([H|T]) ->
+ [H | reinsert_nl(T)];
+reinsert_nl([]) ->
+ [].
+
+%% sgmls treats line breaks in a way that DocBuilder relies on and
+%% which must be imitated here. Replace all "\n" with "\\n" and add
+%% "\n" to the end of each text element.
+nl("") ->
+ "\n";
+nl("\n"++Text) ->
+ "\\n"++nl(Text);
+nl([Ch|Text]) ->
+ [Ch|nl(Text)].
+
+
+%% strip_leading_blanks(Str) -> Str
+%% Leading spaces and tabs before a newline are always redundant
+%% and are therefore stripped of here
+%% If no newline is found the original string is returned unchanged
+
+strip_leading_blanks(Str) ->
+ strip_leading_blanks(Str,Str).
+
+strip_leading_blanks([],Str) ->
+ Str;
+strip_leading_blanks([$\s|T],Str) ->
+ strip_leading_blanks(T,Str);
+strip_leading_blanks([$\t|T],Str) ->
+ strip_leading_blanks(T,Str);
+strip_leading_blanks(Rest=[$\n|_],_) ->
+ Rest;
+strip_leading_blanks(_,Str) ->
+ Str.
+
+%% strip_nl(Str) -> Str
+%% The XMerL scan will often result in the contents of <pre> or <code>
+%% starting with a newline, as the format is normally:
+%% <pre>
+%% ..contents..
+%% </pre>
+%% However, this newline must be removed, or the resulting HTML will be
+%% <pre>
+%%
+%% ..content..
+%% </pre>
+strip_nl({pcdata,[],"\\n"++Str}) -> {pcdata,[],Str};
+strip_nl(E) -> E.
+
+get_dtd([]) ->
+ none;
+get_dtd(Parents) ->
+ {DTD, _} = lists:last(Parents),
+ DTD.
+
+%% attrs(DTD, Tag, GivenAttrs) -> AllAttrs
+%% DTD = Tag = atom() DTD and tag name
+%% GivenAttrs = [#xmlAttribute{}]
+%% AllAttrs = [{Name, Type, Val}]
+%% Name = string() (uppercase) Example: "VALIGN"
+%% Type = "CDATA" | "TOKEN"
+%% Val = string() (uppercase if type is "TOKEN", as-is otherwise)
+%% The XMerL scanning of <file>.xml renders only the given attributes.
+%% However, DocBuilder needs also the optional attributes (which not
+%% necessarily have been given), so we add them here, using the default
+%% values according to the DTDs.
+%% NOTE: Uses the information from the DTDs. That is, if some change is
+%% done to the DTDs, also this file must be updated. Ideally, the DTDs
+%% should be parsed automatically in some way.
+%% It can also be noted that this check is superfluous in the case where
+%% all attributes are required (except that the attributes are sorted
+%% in the same order as in the DTD) and where an optional attribute has
+%% type "CDATA" as no sensible default value can be specified in this
+%% case.
+attrs(DTD, Tag, GivenAttrs) ->
+ merge_attrs(Tag, default_attrs(DTD, Tag), GivenAttrs).
+
+merge_attrs(Tag, [{NameA, Type, DefVal}|Default], GivenAttrs) ->
+ Val = case lists:keysearch(NameA, #xmlAttribute.name, GivenAttrs) of
+ {value, #xmlAttribute{value=Val0}} -> Val0;
+ false -> DefVal
+ end,
+ Attr = {attr_name(NameA), Type, attr_val(Type, Val)},
+ [Attr | merge_attrs(Tag, Default, GivenAttrs)];
+merge_attrs(_Tag, [], _GivenAttrs) ->
+ [].
+
+attr_name(Atom) ->
+ string:to_upper(atom_to_list(Atom)).
+
+attr_val("CDATA", Val) -> Val;
+attr_val("TOKEN", Val) -> string:to_upper(Val).
+
+%% Given the DTD and element tag, return a list [{Name, Value}] where
+%% Name (atom) is the name of each possible attribute and
+%% Value (lowercase string) its default value.
+default_attrs(_, cell) ->
+ [{align, "TOKEN", "left"},
+ {valign, "TOKEN", "middle"}];
+default_attrs(_, cite) ->
+ [{id, "CDATA", ""}]; % required
+default_attrs(_, code) ->
+ [{type, "TOKEN", "none"}];
+default_attrs(_, codeinclude) ->
+ [{file, "CDATA", ""}, % required
+ {tag, "CDATA", ""},
+ {type, "TOKEN", "none"}];
+default_attrs(book, contents) ->
+ [{level, "TOKEN", "2"}];
+default_attrs(_, erleval) ->
+ [{expr, "CDATA", ""}]; % required
+default_attrs(report, erlinclude) ->
+ [{file, "CDATA", ""}, % required
+ {tag, "CDATA", ""}]; % required
+default_attrs(_, fascicule) ->
+ [{file, "CDATA", ""}, % required
+ {href, "CDATA", ""}, % required
+ {entry, "TOKEN", "no"}];
+default_attrs(book, header) ->
+ [{titlestyle, "TOKEN", "normal"}];
+default_attrs(_, image) ->
+ [{file, "CDATA", ""}]; % required
+default_attrs(_, include) ->
+ [{file, "CDATA", ""}]; % required
+default_attrs(report, index) ->
+ [{txt, "CDATA", ""}]; % required
+default_attrs(_, list) ->
+ [{type, "TOKEN", "bulleted"}];
+default_attrs(_, marker) ->
+ [{id, "CDATA", ""}]; % required
+default_attrs(book, onepart) ->
+ [{lift, "TOKEN", "no"}];
+default_attrs(book, parts) ->
+ [{lift, "TOKEN", "no"}];
+default_attrs(_, path) ->
+ [{unix, "CDATA", ""},
+ {windows, "CDATA", ""}];
+default_attrs(_, seealso) ->
+ [{marker, "CDATA", ""}]; % required
+default_attrs(report, table) ->
+ [{width, "CDATA", "0"},
+ {colspec, "CDATA", ""}];
+default_attrs(_, table) ->
+ [{align, "TOKEN", "center"}];
+default_attrs(_, term) ->
+ [{id, "CDATA", ""}]; % required
+default_attrs(book, theheader) ->
+ [{tag, "TOKEN", "none"}];
+default_attrs(bookinsidecover, theheader) ->
+ [{tag, "TOKEN", "none"}];
+default_attrs(_, url) ->
+ [{href, "CDATA", ""}]; % required
+default_attrs(_, _) -> [].
+
+%%--Single PCDATA broken into several fix-------------------------------
+
+%% When text contains an entity, then XMERL splits it into two
+%% PCDATA elements, the second starting with the entity.
+%%
+%% Example:
+%% Magnus Fr�berg => [{pcdata,[],"Magnus Fr\n"},{pcdata,[],"�berg\n"}]
+%%
+%% This is not handled by DocBuilder which expects many tags, for
+%% example title and aname, to contain a single PCDATA element. (That
+%% is also what nsgmls returned.)
+
+fix_single_pcdata([{pcdata,[],Str1}, {pcdata,[],Str2}|T]) ->
+ fix_single_pcdata([{pcdata,[],Str1++Str2}|T]);
+fix_single_pcdata(FixedData) ->
+ FixedData.
+
+tag_content(aname) -> single_pcdata;
+tag_content(app) -> single_pcdata;
+tag_content(approved) -> single_pcdata;
+tag_content(appsummary) -> single_pcdata;
+tag_content(b) -> single_pcdata;
+tag_content(c) -> single_pcdata;
+tag_content(cauthor) -> single_pcdata;
+tag_content(cell) -> mixed_content;
+tag_content(checked) -> single_pcdata;
+tag_content(chowpublished) -> single_pcdata;
+tag_content(code) -> single_pcdata; % mixed?
+tag_content(com) -> single_pcdata;
+tag_content(comsummary) -> single_pcdata;
+tag_content(copyright) -> mixed_content;
+tag_content(ctitle) -> single_pcdata;
+tag_content(d) -> mixed_content;
+tag_content(date) -> single_pcdata;
+tag_content(docno) -> single_pcdata;
+tag_content(em) -> mixed_content;
+tag_content(email) -> single_pcdata;
+tag_content(fascicule) -> single_pcdata;
+tag_content(file) -> single_pcdata;
+tag_content(filesummary) -> single_pcdata;
+tag_content(fsummary) -> mixed_content;
+tag_content(headline) -> single_pcdata;
+tag_content(holder) -> single_pcdata;
+tag_content(i) -> single_pcdata;
+tag_content(icaption) -> single_pcdata;
+tag_content(id) -> single_pcdata;
+tag_content(input) -> mixed_content;
+tag_content(item) -> mixed_content;
+tag_content(legalnotice) -> single_pcdata;
+tag_content(lib) -> single_pcdata;
+tag_content(libsummary) -> single_pcdata;
+tag_content(module) -> single_pcdata;
+tag_content(modulesummary) -> single_pcdata;
+tag_content(name) -> single_pcdata;
+tag_content(nametext) -> single_pcdata;
+tag_content(p) -> mixed_content;
+tag_content(pagetext) -> single_pcdata;
+tag_content(path) -> single_pcdata; % mixed?
+tag_content(pre) -> mixed_content;
+tag_content(prepared) -> single_pcdata;
+tag_content(resp) -> single_pcdata;
+tag_content(responsible) -> single_pcdata;
+tag_content(ret) -> single_pcdata;
+tag_content(rev) -> single_pcdata;
+tag_content(seealso) -> single_pcdata; % mixed?
+tag_content(shortdef) -> single_pcdata;
+tag_content(shorttitle) -> single_pcdata;
+tag_content(tag) -> mixed_content;
+tag_content(tcaption) -> single_pcdata;
+tag_content(termdef) -> single_pcdata;
+tag_content(title) -> single_pcdata;
+tag_content(url) -> single_pcdata; % mixed
+tag_content(v) -> single_pcdata;
+tag_content(year) -> single_pcdata;
+tag_content(_) -> no_pcdata.
+
+
diff --git a/lib/docbuilder/src/docb_xmerl_xml_cb.erl b/lib/docbuilder/src/docb_xmerl_xml_cb.erl
new file mode 100644
index 0000000000..089b8f0c7d
--- /dev/null
+++ b/lib/docbuilder/src/docb_xmerl_xml_cb.erl
@@ -0,0 +1,88 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the Licence for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
+%% All Rights Reserved.��
+%%
+%% $Id$
+%%
+-module(docb_xmerl_xml_cb).
+
+%% This is the callback module for exporting XHTML to a DocBuilder
+%% erlref or chapter document in XML format.
+%% See docb_edoc_xml_cb.erl for further information.
+%%
+%% The origin of this file is the xmerl module xmerl_otpsgml.erl
+%% written by Ulf Wiger and Richard Carlsson.
+
+-export(['#xml-inheritance#'/0]).
+
+-export(['#root#'/4,
+ '#element#'/5,
+ '#text#'/1]).
+
+-include("xmerl.hrl").
+
+'#xml-inheritance#'() ->
+ [xmerl_xml].
+
+'#root#'(Data, _Attrs, [], _E) ->
+ ["<",DTD,">"] = hd(hd(Data)),
+ ["<?xml version=\"1.0\" encoding=\"latin1\" ?>\n",
+ "<!DOCTYPE "++DTD++" SYSTEM \""++DTD++".dtd\">\n",
+ Data].
+
+'#element#'(Tag, Data, Attrs, _Parents, _E) ->
+ {NewTag, NewAttrs} = convert_tag(Tag, Attrs),
+ xmerl_lib:markup(NewTag, NewAttrs, Data).
+
+'#text#'(Text) ->
+ xmerl_lib:export_text(Text).
+
+%% Utility functions
+
+convert_tag(a, [Attr]) ->
+ case Attr#xmlAttribute.name of
+ href ->
+ Val = Attr#xmlAttribute.value,
+ case is_url(Val) of
+ true ->
+ {url, [Attr]};
+ false ->
+ {seealso, [Attr#xmlAttribute{name=marker}]}
+ end;
+ name ->
+ {marker, [Attr#xmlAttribute{name=id}]}
+ end;
+convert_tag(b, Attrs) -> {em, Attrs};
+convert_tag(blockquote, Attrs) -> {quote, Attrs};
+convert_tag(code, Attrs) -> {c, Attrs};
+convert_tag(dd, Attrs) -> {item, Attrs};
+convert_tag(dl, Attrs) -> {taglist, Attrs};
+convert_tag(dt, Attrs) -> {tag, Attrs};
+convert_tag(li, Attrs) -> {item, Attrs};
+convert_tag(ol, Attrs) -> {list, Attrs};
+convert_tag(strong, Attrs) -> {em, Attrs};
+convert_tag(td, Attrs) -> {cell, Attrs};
+convert_tag(tr, Attrs) -> {row, Attrs};
+convert_tag(tt, Attrs) -> {c, Attrs};
+convert_tag(ul, Attrs) -> {list, Attrs};
+convert_tag(underline, Attrs) -> {em, Attrs};
+convert_tag(Tag, Attrs) -> {Tag, Attrs}.
+
+is_url("http:"++_) -> true;
+is_url("../"++_) -> true;
+is_url(FileRef) ->
+ case filename:extension(FileRef) of
+ "" -> false; % no extension = xml file, DocBuilder resolves
+ _Ext -> true % extension, DocBuilder must not resolve
+ end.
diff --git a/lib/docbuilder/src/docb_xml_check.erl b/lib/docbuilder/src/docb_xml_check.erl
new file mode 100644
index 0000000000..8ae5cd2eac
--- /dev/null
+++ b/lib/docbuilder/src/docb_xml_check.erl
@@ -0,0 +1,44 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
+%% Utvecklings AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(docb_xml_check).
+
+-export([validate/1]).
+
+%% validate(File) -> ok | error | {error, badfile}
+%% File = string(), file name with or without ".xml" extension
+%% If XML validation fails for a file, the error information from
+%% Xmerl is printed to terminal and the function returns error.
+validate(File0) ->
+ File = case filename:extension(File0) of
+ ".xml" -> File0;
+ _ -> File0++".xml"
+ end,
+ case filelib:is_regular(File) of
+ true ->
+ DtdDir = docb_util:dtd_dir(),
+ case catch xmerl_scan:file(File, [{validation,true},
+ {fetch_path,[DtdDir]}]) of
+ {'EXIT', Error} ->
+ io:format("~p~n", [Error]),
+ error;
+ {_Doc, _Misc} ->
+ ok
+ end;
+ false ->
+ {error, badfile}
+ end.
diff --git a/lib/docbuilder/src/docbuilder.app.src b/lib/docbuilder/src/docbuilder.app.src
new file mode 100644
index 0000000000..64c4770964
--- /dev/null
+++ b/lib/docbuilder/src/docbuilder.app.src
@@ -0,0 +1,37 @@
+{application, docbuilder,
+ [{description, "Tool for building HTML documentation"},
+ {vsn, "%VSN%"},
+ {modules, [docb_edoc_xml_cb,
+ docb_gen,
+ docb_html,
+ docb_html_layout,
+ docb_html_ref,
+ docb_html_util,
+ docb_html_util_iso,
+ docb_main,
+ docb_pretty_format,
+ docb_tr_application2html,
+ docb_tr_appref2html,
+ docb_tr_chapter2html,
+ docb_tr_cite2html,
+ docb_tr_comref2html,
+ docb_tr_cref2html,
+ docb_tr_erlref2html,
+ docb_tr_fileref2html,
+ docb_tr_first2html,
+ docb_tr_index2html,
+ docb_tr_part2html,
+ docb_tr_refs2kwic,
+ docb_tr_report2html,
+ docb_tr_term2html,
+ docb_transform,
+ docb_util,
+ docb_xmerl_tree_cb,
+ docb_xmerl_xml_cb,
+ docb_xml_check
+ ]},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {env, []}]}.
+
+
diff --git a/lib/docbuilder/src/docbuilder.appup.src b/lib/docbuilder/src/docbuilder.appup.src
new file mode 100644
index 0000000000..54a63833e6
--- /dev/null
+++ b/lib/docbuilder/src/docbuilder.appup.src
@@ -0,0 +1 @@
+{"%VSN%",[],[]}.