diff options
Diffstat (limited to 'lib')
761 files changed, 22111 insertions, 21344 deletions
diff --git a/lib/Makefile b/lib/Makefile index 7e52d6e32e..37e8ce06d7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -48,7 +48,7 @@ else diameter \ cosTransactions cosEvent cosTime cosNotification cosProperty \ cosFileTransfer cosEventDomain et megaco webtool \ - xmerl edoc eunit ssh inviso typer docbuilder erl_docgen \ + xmerl edoc eunit ssh inviso typer erl_docgen \ common_test percept dialyzer # dialyzer OTHER_SUB_DIRECTORIES += hipe @@ -60,7 +60,7 @@ else diameter \ cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ - xmerl edoc eunit ssh inviso typer docbuilder erl_docgen \ + xmerl edoc eunit ssh inviso typer erl_docgen \ common_test percept dialyzer # dialyzer OTHER_SUB_DIRECTORIES += hipe $(TSP_APP) diff --git a/lib/appmon/doc/src/make.dep b/lib/appmon/doc/src/make.dep deleted file mode 100644 index ce0d7571a3..0000000000 --- a/lib/appmon/doc/src/make.dep +++ /dev/null @@ -1,26 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: appmon.tex appmon_chapter.tex book.tex part.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: app_win.ps listbox_win.ps main_win.ps pinfo_win.ps - diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile index d29225f6c9..566173837c 100644 --- a/lib/asn1/doc/src/Makefile +++ b/lib/asn1/doc/src/Makefile @@ -27,15 +27,6 @@ include ../../vsn.mk VSN=$(ASN1_VSN) APPLICATION=asn1 - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -86,34 +77,10 @@ EXTRA_FILES = \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) \ - $(BOOK_FILES:%.xml=%.sgml) part.tex -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -126,8 +93,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -142,32 +107,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f $(GEN_XML) errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -179,8 +118,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -191,31 +128,4 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(HTML_APPHISTORY) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif - release_spec: - - - diff --git a/lib/asn1/doc/src/make.dep b/lib/asn1/doc/src/make.dep deleted file mode 100644 index eb2c0e9a98..0000000000 --- a/lib/asn1/doc/src/make.dep +++ /dev/null @@ -1,31 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/gandalf/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: asn1_spec.tex asn1_ug.tex asn1ct.tex asn1rt.tex \ - book.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -asn1_spec.tex: Seq.asn Seq.asn1config - -book.tex: part.xml ref_man.xml - -asn1_ug.tex: ../../../../system/doc/definitions/cite.defs - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: exclusive_Win_But.ps selective_TypeList.ps \ - selective_Window2.ps - diff --git a/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn b/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn index 5a5d310729..5a5d310729 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn +++ b/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn diff --git a/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn b/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn index ef236e98a9..ef236e98a9 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn +++ b/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn diff --git a/lib/asn1/test/asn1_SUITE_data/LDAP.asn1 b/lib/asn1/test/asn1_SUITE_data/LDAP.asn1 index 4d845942e1..4d845942e1 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/LDAP.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/LDAP.asn1 diff --git a/lib/asn1/test/asn1_SUITE_data/Nortel.asn b/lib/asn1/test/asn1_SUITE_data/Nortel.asn index a27c78a0b5..a27c78a0b5 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/Nortel.asn +++ b/lib/asn1/test/asn1_SUITE_data/Nortel.asn diff --git a/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn b/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn index 247260495b..247260495b 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn +++ b/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn diff --git a/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn b/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn index d9601bb7d0..d9601bb7d0 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn +++ b/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn index e3f6e83d6b..e3f6e83d6b 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn index 1411d455b7..1411d455b7 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn index fb08451103..fb08451103 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn index 848d8f6099..848d8f6099 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn index 9ecfa688a2..9ecfa688a2 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn index b9be9934e4..b9be9934e4 100755..100644 --- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn +++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index 3ea6ae65d5..964f7c76c1 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -138,12 +138,6 @@ man: $(MAN6_FILES) $(MAN3_FILES) $(MAN1_FILES) debug opt: -# -# checkout make.dep before generating new dependecies -# -#make_doc_depend: xml -# docdepend > make.dep - clean clean_docs: rm -f $(CT_XML_FILES) rm -rf $(HTMLDIR)/* @@ -176,12 +170,3 @@ release_docs_spec: docs release_spec: release_tests_spec: - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -include make.dep -# DO NOT DELETE - - diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml index f9fc1858d0..b98c04a850 100644 --- a/lib/common_test/doc/src/ct_hooks.xml +++ b/lib/common_test/doc/src/ct_hooks.xml @@ -37,12 +37,6 @@ <description> - <warning><p>This feature is in alpha release right now. This means that the - interface may change in the future and that there may be bugs. We - encourage you to use this feature, but be prepared - that there might be bugs and that the interface might change - inbetween releases.</p></warning> - <p>The <em>Common Test Hook</em> (henceforth called CTH) framework allows extensions of the default behaviour of Common Test by means of callbacks before and after all test suite calls. It is meant for advanced users of diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index 3b9620d0f2..bac0c4eaa8 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -32,11 +32,6 @@ <marker id="general"></marker> <section> <title>General</title> - <warning><p>This feature is in alpha release right now. This means that the - interface may change in the future and that there may be bugs. We - encourage you to use this feature, but be prepared - that there might be bugs and that the interface might change - inbetween releases.</p></warning> <p> The <em>Common Test Hook</em> (henceforth called CTH) framework allows extensions of the default behaviour of Common Test by means of hooks diff --git a/lib/common_test/doc/src/filestruct.gif b/lib/common_test/doc/src/filestruct.gif Binary files differindex 2b06833d0b..2b06833d0b 100755..100644 --- a/lib/common_test/doc/src/filestruct.gif +++ b/lib/common_test/doc/src/filestruct.gif diff --git a/lib/common_test/doc/src/make.dep b/lib/common_test/doc/src/make.dep deleted file mode 100644 index e34075888d..0000000000 --- a/lib/common_test/doc/src/make.dep +++ /dev/null @@ -1,27 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: basics_chapter.tex book.tex common_test_app.tex \ - config_file_chapter.tex cover_chapter.tex \ - ct.tex ct_cover.tex ct_ftp.tex ct_master.tex \ - ct_master_chapter.tex ct_rpc.tex ct_snmp.tex \ - ct_ssh.tex ct_telnet.tex dependencies_chapter.tex \ - event_handler_chapter.tex example_chapter.tex \ - install_chapter.tex part.tex ref_man.tex run_test.tex \ - run_test_chapter.tex test_structure_chapter.tex \ - unix_telnet.tex why_test_chapter.tex write_test_chapter.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in index f4a0c181f9..d9033f6ef1 100644 --- a/lib/common_test/priv/Makefile.in +++ b/lib/common_test/priv/Makefile.in @@ -59,6 +59,7 @@ ifneq ($(findstring win32,$(TARGET)),win32) FILES = vts.tool SCRIPTS = IMAGES = tile1.jpg +CSS = ct_default.css # # Rules @@ -85,11 +86,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk ifeq ($(XNIX),true) release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/priv - $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv + $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv else release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/priv - $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv + $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv endif release_docs_spec: @@ -105,6 +106,7 @@ else # FILES = vts.tool IMAGES = tile1.jpg +CSS = ct_default.css # # Rules @@ -124,7 +126,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/priv - $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv + $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv release_docs_spec: diff --git a/lib/common_test/priv/ct_default.css b/lib/common_test/priv/ct_default.css new file mode 100644 index 0000000000..a64e1ec576 --- /dev/null +++ b/lib/common_test/priv/ct_default.css @@ -0,0 +1,186 @@ +/* Stylesheet for Common Test */ + +body { + padding: 10px; margin: 10px; + -webkit-font-smoothing: antialiased; + background-color: #FBFFFC; +} + +a:link { + color: #2B507D; +} + +a:visited { + color: #85ABD5 +} + +h1 { + font-family: verdana, arial, sans-serif; font-size: 200%; + letter-spacing: -2px; word-spacing: 2px; font-weight: bold; + color: #3F3F3F; +} + +h2 { + font-family: verdana, arial, sans-serif; font-size: 175%; + letter-spacing: -2px; word-spacing: 2px; font-weight: normal; + color: #3F3F3F; +} + +h3 { + font-family: verdana, arial, sans-serif; font-size: 140%; + letter-spacing: -2px; word-spacing: 2px; font-weight: bold; + color: #3F3F3F; +} + +h4 { + font-family: verdana, arial, sans-serif; font-size: 120%; + letter-spacing: -2px; word-spacing: 2px; font-weight: normal; + color: #3F3F3F; +} + +p { + font-family: "Trebuchet MS", "Lucida Sans Unicode", verdana, arial, sans-serif; + font-size: .9em; color: #000000; +} + +ul { + list-style-type: none; + padding: 0em; + margin: 1em; +} +li { + font-size: 0.95em; color: #000000; + margin: .3em 0; +} + +pre { + color: black; + font-family: "Monaco", "Andale Mono", "Consolas", monospace; + font-size: .8em; + } + +code { + color: black; + font-family: "Monaco", "Andale Mono", "Consolas", monospace; + font-size: .8em; +} + +div.mono_sm { + font-family: "Courier New", monospace; font-size: .75em; + word-spacing: 1px; color: #000000; +} + +div.mono_la { + font-family: "Courier New", monospace; font-size: .8em; + color: #000000; +} + +div.copyright { + padding: 20px 0px 0px 0px; + font-family: "Courier New", monospace; font-size: .7em; + color: #000000; +} + +div.ct_internal { + background: lightgrey; color: black; + font-family: "Monaco", "Andale Mono", "Consolas", monospace; + font-size: .95em; + margin: .2em 0 0 0; +} + +div.default { + background: lightgreen; color: black; + font-family: "Monaco", "Andale Mono", "Consolas", monospace; + font-size: 1.05em; + margin: .2em 0 0 0; +} + +div.label { + font-family: verdana, arial, sans-serif; font-size: 200%; + letter-spacing: -2.5px; word-spacing: 2px; + font-weight: bold; color: #2B507D; +} + +table { + border-collapse: collapse; border: 6px solid #3F3F3F; + background: #FFFFFF; + font: .8em/1.2em "Lucida Sans Unicode", verdana, arial, sans-serif; + color: #222; +} + +caption { + font-size: 1.3em; font-weight: bold; + text-align: center; padding: 1em 4px; +} + +td, th { + padding: .5em 7px .5em 7px; line-height: 1.3em; + border-bottom: 3px solid #F5C4C1; + border-left: 2px dashed #809FFF; +} + +th { + background: #3F3F3F; color: #fff; + font-family: arial, sans-serif; font-size: 120%; + letter-spacing: -0.5px; + font-weight: bold; text-align: center; + padding-right: .5em; vertical-align: top; +} + +thead th { + background: #2C5755; text-align: center; +} + +.odd td { + background: #F3F3F3; +} +.odd th { + background: #F3F3F3; +} + +td a, td a:link { + color: #2B507D; +} + +td a:visited { + color: #85ABD5; +} + +tr:hover th[scope=row], tr:hover td { + background-color: #808080; + color: #fff; +} + +td a:hover, td a:focus { + color: #85ABD5; +} + +th a, td a:active { + color: #85ABD5; +} + +tfoot th, tfoot td { + background: #3F3F3F; color: #fff; +} + +th + td { + padding-left: .5em; +} + +#button_holder { + display: block; float: center; + font-family: arial, verdana, sans-serif; + font-size: 12px; text-shadow: 1px 1px lightgray; +} + +.btn a { + padding: 6px 12px; float: center; + text-decoration: none; color: #3F3F3F; + font-weight: bold; border: 3px outset #3F3F3F; + background-color: #F3F3F3; +} + +.btn a:hover { + color: #fff; + background-color: #809FFF; +} diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 482c5242ce..0897675591 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -27,7 +27,7 @@ -export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, get_all_cases/1]). -export([report/2, warn/1, error_notification/4]). --export([get_logopts/0, format_comment/1, overview_html_header/1]). +-export([get_logopts/0, format_comment/1, get_html_wrapper/3]). -export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]). @@ -1411,30 +1411,6 @@ format_comment(Comment) -> "<font color=\"green\">" ++ Comment ++ "</font>". %%%----------------------------------------------------------------- -%%% @spec overview_html_header(TestName) -> Header -overview_html_header(TestName) -> - TestName1 = lists:flatten(io_lib:format("~p", [TestName])), - Label = case application:get_env(common_test, test_label) of - {ok,Lbl} when Lbl =/= undefined -> - "<H1><FONT color=\"green\">" ++ Lbl ++ "</FONT></H1>\n"; - _ -> - "" - end, - Bgr = case ct_logs:basic_html() of - true -> - ""; - false -> - CTPath = code:lib_dir(common_test), - TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"), - " background=\"" ++ TileFile ++ "\"" - end, - - ["<html>\n", - "<head><title>Test ", TestName1, " results</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", - "</head>\n", - "<body", Bgr, " bgcolor=\"white\" text=\"black\" ", - "link=\"blue\" vlink=\"purple\" alink=\"red\">\n", - Label, - "<H2>Results from test ", TestName1, "</H2>\n"]. - +%%% @spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header +get_html_wrapper(TestName, PrintLabel, Cwd) -> + ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd). diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index c1523509a5..d66a31d9a5 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -29,11 +29,13 @@ -module(ct_logs). -export([init/1,close/2,init_tc/1,end_tc/1]). --export([get_log_dir/0,log/3,start_log/1,cont_log/2,end_log/0]). +-export([get_log_dir/0,get_log_dir/1]). +-export([log/3,start_log/1,cont_log/2,end_log/0]). -export([set_stylesheet/2,clear_stylesheet/1]). -export([add_external_logs/1,add_link/3]). -export([make_last_run_index/0]). -export([make_all_suites_index/1,make_all_runs_index/1]). +-export([get_ts_html_wrapper/3]). %% Logging stuff directly from testcase -export([tc_log/3,tc_print/3,tc_pal/3,ct_log/3, @@ -53,6 +55,7 @@ -define(all_runs_name, "all_runs.html"). -define(index_name, "index.html"). -define(totals_name, "totals.info"). +-define(css_default, "ct_default.css"). -define(table_color1,"#ADD8E6"). -define(table_color2,"#E4F0FE"). @@ -162,7 +165,12 @@ clear_stylesheet(TC) -> %%%----------------------------------------------------------------- %%% @spec get_log_dir() -> {ok,Dir} | {error,Reason} get_log_dir() -> - call(get_log_dir). + call({get_log_dir,false}). + +%%%----------------------------------------------------------------- +%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason} +get_log_dir(ReturnAbsName) -> + call({get_log_dir,ReturnAbsName}). %%%----------------------------------------------------------------- %%% make_last_run_index() -> ok @@ -205,6 +213,7 @@ cast(Msg) -> %%% <p>This function is called by ct_framework:init_tc/3</p> init_tc(RefreshLog) -> call({init_tc,self(),group_leader(),RefreshLog}), + io:format(xhtml("", "<br />")), ok. %%%----------------------------------------------------------------- @@ -214,6 +223,7 @@ init_tc(RefreshLog) -> %%% %%% <p>This function is called by ct_framework:end_tc/3</p> end_tc(TCPid) -> + io:format(xhtml("<br>", "<br />")), %% use call here so that the TC process will wait and receive %% possible exit signals from ct_logs before end_tc returns ok call({end_tc,TCPid}). @@ -448,7 +458,6 @@ logger(Parent,Mode) -> timer:sleep(1000), Time1 = calendar:local_time(), Dir1 = make_dirname(Time1), - {Time1,Dir1}; false -> {Time0,Dir0} @@ -456,8 +465,44 @@ logger(Parent,Mode) -> %%! <--- file:make_dir(Dir), + AbsDir = ?abs(Dir), + put(ct_run_dir, AbsDir), + + case basic_html() of + true -> + put(basic_html, true); + BasicHtml -> + put(basic_html, BasicHtml), + %% copy stylesheet to log dir (both top dir and test run + %% dir) so logs are independent of Common Test installation + {ok,Cwd} = file:get_cwd(), + CTPath = code:lib_dir(common_test), + CSSFileSrc = filename:join(filename:join(CTPath, "priv"), + ?css_default), + CSSFileDestTop = filename:join(Cwd, ?css_default), + CSSFileDestRun = filename:join(AbsDir, ?css_default), + case file:copy(CSSFileSrc, CSSFileDestTop) of + {error,Reason0} -> + io:format(user, "ERROR! "++ + "CSS file ~p could not be copied to ~p. "++ + "Reason: ~p~n", + [CSSFileSrc,CSSFileDestTop,Reason0]), + exit({css_file_error,CSSFileDestTop}); + _ -> + case file:copy(CSSFileSrc, CSSFileDestRun) of + {error,Reason1} -> + io:format(user, "ERROR! "++ + "CSS file ~p could not be copied to ~p. "++ + "Reason: ~p~n", + [CSSFileSrc,CSSFileDestRun,Reason1]), + exit({css_file_error,CSSFileDestRun}); + _ -> + ok + end + end + end, ct_event:notify(#event{name=start_logging,node=node(), - data=?abs(Dir)}), + data=AbsDir}), make_all_runs_index(start), make_all_suites_index(start), case Mode of @@ -472,7 +517,7 @@ logger(Parent,Mode) -> Parent ! {started,self(),{Time,filename:absname("")}}, set_evmgr_gl(CtLogFd), logger_loop(#logger_state{parent=Parent, - log_dir=Dir, + log_dir=AbsDir, start_time=Time, orig_GL=group_leader(), ct_log_fd=CtLogFd, @@ -536,12 +581,15 @@ logger_loop(State) -> set_evmgr_gl(State#logger_state.ct_log_fd), return(From,ok), logger_loop(State#logger_state{tc_groupleaders=rm_tc_gl(TCPid,State)}); - {get_log_dir,From} -> + {{get_log_dir,true},From} -> return(From,{ok,State#logger_state.log_dir}), logger_loop(State); + {{get_log_dir,false},From} -> + return(From,{ok,filename:basename(State#logger_state.log_dir)}), + logger_loop(State); {make_last_run_index,From} -> make_last_run_index(State#logger_state.start_time), - return(From,State#logger_state.log_dir), + return(From,filename:basename(State#logger_state.log_dir)), logger_loop(State); {set_stylesheet,_,SSFile} when State#logger_state.stylesheet == SSFile -> logger_loop(State); @@ -657,7 +705,7 @@ set_evmgr_gl(GL) -> open_ctlog() -> {ok,Fd} = file:open(?ct_log_name,[write]), - io:format(Fd,header("Common Test Framework"),[]), + io:format(Fd, header("Common Test Framework Log"), []), case file:consult(ct_run:variables_file_name("../")) of {ok,Vars} -> io:format(Fd, config_table(Vars), []); @@ -672,17 +720,22 @@ open_ctlog() -> end, print_style(Fd,undefined), io:format(Fd, - "<br><br><h2>Progress Log</h2>\n" - "<pre>\n",[]), + xhtml("<br><br><h2>Progress Log</h2>\n<pre>\n", + "<br /><br /><h4>PROGRESS LOG</h4>\n<pre>\n"), []), Fd. print_style(Fd,undefined) -> - io:format(Fd, - "<style>\n" - "div.ct_internal { background:lightgrey; color:black }\n" - "div.default { background:lightgreen; color:black }\n" - "</style>\n", - []); + case basic_html() of + true -> + io:format(Fd, + "<style>\n" + "div.ct_internal { background:lightgrey; color:black; }\n" + "div.default { background:lightgreen; color:black; }\n" + "</style>\n", + []); + _ -> + ok + end; print_style(Fd,StyleSheet) -> case file:read_file(StyleSheet) of @@ -723,7 +776,7 @@ print_style_error(Fd,StyleSheet,Reason) -> print_style(Fd,undefined). close_ctlog(Fd) -> - io:format(Fd,"</pre>",[]), + io:format(Fd,"\n</pre>\n",[]), io:format(Fd,footer(),[]), file:close(Fd). @@ -854,8 +907,8 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, CrashDumpName = SuiteName ++ "_erl_crash.dump", case filelib:is_file(CrashDumpName) of true -> - [" <A HREF=\"", CrashDumpName, - "\">(CrashDump)</A>"]; + [" <a href=\"", CrashDumpName, + "\">(CrashDump)</a>"]; false -> "" end @@ -869,32 +922,41 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, 0 -> "-"; _ -> NodeOrDate end, - N = ["<TD ALIGN=right><FONT SIZE=-1>",Node1,"</FONT></TD>\n"], - L = ["<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</FONT></B></TD>\n"], - T = ["<TD><FONT SIZE=-1>",timestamp(CtRunDir),"</FONT></TD>\n"], + TS = timestamp(CtRunDir), + N = xhtml(["<td align=right><font size=\"-1\">",Node1, + "</font></td>\n"], + ["<td align=right>",Node1,"</td>\n"]), + L = xhtml(["<td align=center><font size=\"-1\"><b>",Label, + "</font></b></td>\n"], + ["<td align=center><b>",Label,"</b></td>\n"]), + T = xhtml(["<td><font size=\"-1\">",TS,"</font></td>\n"], + ["<td>",TS,"</td>\n"]), CtLogFile = filename:join(CtRunDir,?ct_log_name), OldRunsLink = case OldRuns of [] -> "none"; - _ -> "<A HREF=\""++?all_runs_name++"\">Old Runs</A>" + _ -> "<a href=\""++?all_runs_name++"\">Old Runs</a>" end, - A=["<TD><FONT SIZE=-1><A HREF=\"",CtLogFile,"\">CT Log</A></FONT></TD>\n", - "<TD><FONT SIZE=-1>",OldRunsLink,"</FONT></TD>\n"], + A = xhtml(["<td><font size=\"-1\"><a href=\"",CtLogFile, + "\">CT Log</a></font></td>\n", + "<td><font size=\"-1\">",OldRunsLink,"</font></td>\n"], + ["<td><a href=\"",CtLogFile,"\">CT Log</a></td>\n", + "<td>",OldRunsLink,"</td>\n"]), {L,T,N,A}; false -> {"","","",""} end, NotBuiltStr = if NotBuilt == 0 -> - ["<TD ALIGN=right>",integer_to_list(NotBuilt),"</TD>\n"]; + ["<td align=right>",integer_to_list(NotBuilt),"</td>\n"]; true -> - ["<TD ALIGN=right><A HREF=\"",filename:join(CtRunDir,?ct_log_name),"\">", - integer_to_list(NotBuilt),"</A></TD>\n"] + ["<td align=right><a href=\"",filename:join(CtRunDir,?ct_log_name),"\">", + integer_to_list(NotBuilt),"</a></td>\n"] end, FailStr = if Fail > 0 -> - ["<FONT color=\"red\">", - integer_to_list(Fail),"</FONT>"]; + ["<font color=\"red\">", + integer_to_list(Fail),"</font>"]; true -> integer_to_list(Fail) end, @@ -902,31 +964,33 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, if AutoSkip == undefined -> {UserSkip,"?","?"}; true -> ASStr = if AutoSkip > 0 -> - ["<FONT color=\"brown\">", - integer_to_list(AutoSkip),"</FONT>"]; + ["<font color=\"brown\">", + integer_to_list(AutoSkip),"</font>"]; true -> integer_to_list(AutoSkip) end, {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr} end, - ["<TR valign=top>\n", - "<TD><FONT SIZE=-1><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</FONT></TD>\n", - Lbl, - Timestamp, - "<TD ALIGN=right>",integer_to_list(Success),"</TD>\n", - "<TD ALIGN=right>",FailStr,"</TD>\n", - "<TD ALIGN=right>",integer_to_list(AllSkip), - " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n", - NotBuiltStr, - Node, - AllInfo, - "</TR>\n"]. + [xhtml("<tr valign=top>\n", + ["<tr class=\"",odd_or_even(),"\">\n"]), + xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""), + LogFile,"\">",SuiteName,"</a>", CrashDumpLink, + xhtml("</font></td>\n", "</td>\n"), + Lbl, Timestamp, + "<td align=right>",integer_to_list(Success),"</td>\n", + "<td align=right>",FailStr,"</td>\n", + "<td align=right>",integer_to_list(AllSkip), + " (",UserSkipStr,"/",AutoSkipStr,")</td>\n", + NotBuiltStr, Node, AllInfo, "</tr>\n"]. + total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) -> {Label,TimestampCell,AllInfo} = case All of true -> - {"<TD> </TD>\n", - "<TD> </TD>\n", - "<TD> </TD>\n<TD> </TD>\n"}; + {"<td> </td>\n", + "<td> </td>\n", + "<td> </td>\n" + "<td> </td>\n" + "<td> </td>\n"}; false -> {"","",""} end, @@ -936,17 +1000,15 @@ total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) -> true -> {UserSkip+AutoSkip, integer_to_list(UserSkip),integer_to_list(AutoSkip)} end, - ["<TR valign=top>\n", - "<TD><B>Total</B></TD>", - Label, - TimestampCell, - "<TD ALIGN=right><B>",integer_to_list(Success),"<B></TD>\n", - "<TD ALIGN=right><B>",integer_to_list(Fail),"<B></TD>\n", - "<TD ALIGN=right>",integer_to_list(AllSkip), - " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n", - "<TD ALIGN=right><B>",integer_to_list(NotBuilt),"<B></TD>\n", - AllInfo, - "</TR>\n"]. + [xhtml("<tr valign=top>\n", + ["<tr class=\"",odd_or_even(),"\">\n"]), + "<td><b>Total</b></td>\n", Label, TimestampCell, + "<td align=right><b>",integer_to_list(Success),"<b></td>\n", + "<td align=right><b>",integer_to_list(Fail),"<b></td>\n", + "<td align=right>",integer_to_list(AllSkip), + " (",UserSkipStr,"/",AutoSkipStr,")</td>\n", + "<td align=right><b>",integer_to_list(NotBuilt),"<b></td>\n", + AllInfo, "</tr>\n"]. not_built(_BaseName,_LogDir,_All,[]) -> 0; @@ -1005,41 +1067,52 @@ index_header(Label, StartTime) -> undefined -> header("Test Results", format_time(StartTime)); _ -> - header("Test Results for \"" ++ Label ++ "\"", + header("Test Results for '" ++ Label ++ "'", format_time(StartTime)) end, [Head | - ["<CENTER>\n", - "<P><A HREF=\"",?ct_log_name,"\">Common Test Framework Log</A></P>", - "<TABLE border=\"3\" cellpadding=\"5\" " - "BGCOLOR=\"",?table_color3,"\">\n" - "<th><B>Test Name</B></th>\n", - "<th><font color=\"",?table_color3,"\">_</font>Ok" - "<font color=\"",?table_color3,"\">_</font></th>\n" + ["<center>\n", + xhtml(["<p><a href=\"",?ct_log_name, + "\">Common Test Framework Log</a></p>"], + ["<br />" + "<div id=\"button_holder\" class=\"btn\">\n" + "<a href=\"",?ct_log_name, + "\">COMMON TEST FRAMEWORK LOG</a>\n</div>"]), + xhtml("<br>\n", "<br /><br /><br />\n"), + xhtml(["<table border=\"3\" cellpadding=\"5\" " + "bgcolor=\"",?table_color3,"\">\n"], "<table>\n"), + "<th><b>Test Name</b></th>\n", + xhtml(["<th><font color=\"",?table_color3,"\">_</font>Ok" + "<font color=\"",?table_color3,"\">_</font></th>\n"], + "<th>Ok</th>\n"), "<th>Failed</th>\n", - "<th>Skipped<br>(User/Auto)</th>\n" - "<th>Missing<br>Suites</th>\n" + "<th>Skipped", xhtml("<br>", "<br />"), "(User/Auto)</th>\n" + "<th>Missing", xhtml("<br>", "<br />"), "Suites</th>\n" "\n"]]. - all_suites_index_header() -> {ok,Cwd} = file:get_cwd(), all_suites_index_header(Cwd). all_suites_index_header(IndexDir) -> LogDir = filename:basename(IndexDir), - AllRuns = "All test runs in \"" ++ LogDir ++ "\"", + AllRuns = xhtml(["All test runs in \"" ++ LogDir ++ "\""], + "ALL RUNS"), + AllRunsLink = xhtml(["<a href=\"",?all_runs_name,"\">",AllRuns,"</a>\n"], + ["<div id=\"button_holder\" class=\"btn\">\n" + "<a href=\"",?all_runs_name,"\">",AllRuns,"</a>\n</div>"]), [header("Test Results") | - ["<CENTER>\n", - "<A HREF=\"",?all_runs_name,"\">",AllRuns,"</A>\n", - "<br><br>\n", - "<TABLE border=\"3\" cellpadding=\"5\" " - "BGCOLOR=\"",?table_color2,"\">\n" + ["<center>\n", + AllRunsLink, + xhtml("<br><br>\n", "<br /><br />\n"), + xhtml(["<table border=\"3\" cellpadding=\"5\" " + "bgcolor=\"",?table_color2,"\">\n"], "<table>\n"), "<th>Test Name</th>\n", "<th>Label</th>\n", "<th>Test Run Started</th>\n", - "<th><font color=\"",?table_color2,"\">_</font>Ok" - "<font color=\"",?table_color2,"\">_</font></th>\n" + xhtml(["<th><font color=\"",?table_color2,"\">_</font>Ok" + "<font color=\"",?table_color2,"\">_</font></th>\n"], + "<th>Ok</th>\n"), "<th>Failed</th>\n", "<th>Skipped<br>(User/Auto)</th>\n" "<th>Missing<br>Suites</th>\n" @@ -1052,17 +1125,25 @@ all_runs_header() -> {ok,Cwd} = file:get_cwd(), LogDir = filename:basename(Cwd), Title = "All test runs in \"" ++ LogDir ++ "\"", + IxLink = [xhtml(["<p><a href=\"",?index_name, + "\">Test Index Page</a></p>"], + ["<div id=\"button_holder\" class=\"btn\">\n" + "<a href=\"",?index_name, + "\">TEST INDEX PAGE</a>\n</div>"]), + xhtml("<br>\n", "<br /><br />\n")], [header(Title) | - ["<CENTER><TABLE border=\"3\" cellpadding=\"5\" " - "BGCOLOR=\"",?table_color1,"\">\n" - "<th><B>History</B></th>\n" - "<th><B>Node</B></th>\n" - "<th><B>Label</B></th>\n" + ["<center>\n", IxLink, + xhtml(["<table border=\"3\" cellpadding=\"5\" " + "bgcolor=\"",?table_color1,"\">\n"], "<table>\n"), + "<th><b>History</b></th>\n" + "<th><b>Node</b></th>\n" + "<th><b>Label</b></th>\n" "<th>Tests</th>\n" - "<th><B>Test Names</B></th>\n" - "<th>Total</th>\n" - "<th><font color=\"",?table_color1,"\">_</font>Ok" - "<font color=\"",?table_color1,"\">_</font></th>\n" + "<th><b>Test Names</b></th>\n" + "<th>Total</th>\n", + xhtml(["<th><font color=\"",?table_color1,"\">_</font>Ok" + "<font color=\"",?table_color1,"\">_</font></th>\n"], + "<th>Ok</th>\n"), "<th>Failed</th>\n" "<th>Skipped<br>(User/Auto)</th>\n" "<th>Missing<br>Suites</th>\n" @@ -1075,60 +1156,56 @@ header(Title, SubTitle) -> header1(Title, SubTitle) -> SubTitleHTML = if SubTitle =/= "" -> - ["<CENTER>\n", - "<H2>" ++ SubTitle ++ "</H2>\n", - "</CENTER>\n<BR>\n"]; - true -> "<BR>\n" + ["<center>\n", + "<h3>" ++ SubTitle ++ "</h3>\n", + xhtml("</center>\n<br>\n", "</center>\n<br />\n")]; + true -> xhtml("<br>\n", "<br />\n") end, - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<HTML>\n", - "<HEAD>\n", - - "<TITLE>" ++ Title ++ " " ++ SubTitle ++ "</TITLE>\n", - "<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE\">\n", - - "</HEAD>\n", - - body_tag(), - - "<!-- ---- DOCUMENT TITLE ---- -->\n", - - "<CENTER>\n", - "<H1>" ++ Title ++ "</H1>\n", - "</CENTER>\n", - SubTitleHTML, - - "<!-- ---- CONTENT ---- -->\n"]. + CSSFile = xhtml(fun() -> "" end, + fun() -> make_relative(locate_default_css_file()) end), + [xhtml(["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", + "<html>\n"], + ["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n", + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n", + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"]), + "<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n", + "<head>\n", + "<title>" ++ Title ++ " " ++ SubTitle ++ "</title>\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + xhtml("", + ["<link rel=\"stylesheet\" href=\"",CSSFile,"\" type=\"text/css\">"]), + "</head>\n", + body_tag(), + "<center>\n", + "<h1>" ++ Title ++ "</h1>\n", + "</center>\n", + SubTitleHTML,"\n"]. index_footer() -> - ["</TABLE>\n" - "</CENTER>\n" | footer()]. + ["</table>\n" + "</center>\n" | footer()]. footer() -> - ["<P><CENTER>\n" - "<BR><BR>\n" - "<HR>\n" - "<P><FONT SIZE=-1>\n" + ["<center>\n", + xhtml("<br><br>\n<hr>\n", "<br /><br />\n"), + xhtml("<p><font size=\"-1\">\n", "<div class=\"copyright\">"), "Copyright © ", year(), - " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n" - "Updated: <!date>", current_time(), "<!/date><BR>\n" - "</FONT>\n" - "</CENTER>\n" + " <a href=\"http://www.erlang.org\">Open Telecom Platform</a>", + xhtml("<br>\n", "<br />\n"), + "Updated: <!date>", current_time(), "<!/date>", + xhtml("<br>\n", "<br />\n"), + xhtml("</font></p>\n", "</div>\n"), + "</center>\n" "</body>\n"]. body_tag() -> - case basic_html() of - true -> - "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" " - "vlink=\"#800080\" alink=\"#FF0000\">\n"; - false -> - CTPath = code:lib_dir(common_test), - TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"), - "<body background=\"" ++ TileFile ++ "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" " - "vlink=\"#800080\" alink=\"#FF0000\">\n" - end. + CTPath = code:lib_dir(common_test), + TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"), + xhtml("<body background=\"" ++ TileFile ++ + "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" " + "vlink=\"#800080\" alink=\"#FF0000\">\n", + "<body>\n"). current_time() -> format_time(calendar:local_time()). @@ -1258,20 +1335,25 @@ config_table(Vars) -> [config_table_header()|config_table1(Vars)]. config_table_header() -> - ["<h2>Configuration</h2>\n", - "<table border=\"3\" cellpadding=\"5\" bgcolor=\"",?table_color1, - "\"\n", + [ + xhtml(["<h2>Configuration</h2>\n" + "<table border=\"3\" cellpadding=\"5\" bgcolor=\"",?table_color1,"\"\n"], + "<h4>CONFIGURATION</h4>\n<table>\n"), "<tr><th>Key</th><th>Value</th></tr>\n"]. config_table1([{Key,Value}|Vars]) -> - ["<tr><td>", atom_to_list(Key), "</td>\n", - "<td><pre>",io_lib:format("~p",[Value]),"</pre></td></tr>\n" | + [xhtml(["<tr><td>", atom_to_list(Key), "</td>\n", + "<td><pre>",io_lib:format("~p",[Value]),"</pre></td></tr>\n"], + ["<tr class=\"", odd_or_even(), "\">\n", + "<td>", atom_to_list(Key), "</td>\n", + "<td>", io_lib:format("~p",[Value]), "</td>\n</tr>\n"]) | config_table1(Vars)]; config_table1([]) -> ["</table>\n"]. make_all_runs_index(When) -> + put(basic_html, basic_html()), AbsName = ?abs(?all_runs_name), notify_and_lock_file(AbsName), if When == start -> ok; @@ -1280,8 +1362,7 @@ make_all_runs_index(When) -> Dirs = filelib:wildcard(logdir_prefix()++"*.*"), DirsSorted = (catch sort_all_runs(Dirs)), Header = all_runs_header(), - BasicHtml = basic_html(), - Index = [runentry(Dir, BasicHtml) || Dir <- DirsSorted], + Index = [runentry(Dir) || Dir <- DirsSorted], Result = file:write_file(AbsName,Header++Index++index_footer()), if When == start -> ok; true -> io:put_chars("done\n") @@ -1309,22 +1390,22 @@ sort_all_runs(Dirs) -> interactive_link() -> [Dir|_] = lists:reverse(filelib:wildcard(logdir_prefix()++"*.*")), CtLog = filename:join(Dir,"ctlog.html"), - Body = ["Log from last interactive run: <A HREF=\"",CtLog,"\">", - timestamp(Dir),"</A>"], + Body = ["Log from last interactive run: <a href=\"",CtLog,"\">", + timestamp(Dir),"</a>"], file:write_file("last_interactive.html",Body), io:format("~n~nUpdated ~s\n" "Any CT activities will be logged here\n", [?abs("last_interactive.html")]). -runentry(Dir, BasicHtml) -> +runentry(Dir) -> TotalsFile = filename:join(Dir,?totals_name), TotalsStr = case read_totals_file(TotalsFile) of {Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} -> TotFailStr = if TotFail > 0 -> - ["<FONT color=\"red\">", - integer_to_list(TotFail),"</FONT>"]; + ["<font color=\"red\">", + integer_to_list(TotFail),"</font>"]; true -> integer_to_list(TotFail) end, @@ -1332,8 +1413,8 @@ runentry(Dir, BasicHtml) -> if AutoSkip == undefined -> {UserSkip,"?","?"}; true -> ASStr = if AutoSkip > 0 -> - ["<FONT color=\"brown\">", - integer_to_list(AutoSkip),"</FONT>"]; + ["<font color=\"brown\">", + integer_to_list(AutoSkip),"</font>"]; true -> integer_to_list(AutoSkip) end, {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr} @@ -1365,30 +1446,49 @@ runentry(Dir, BasicHtml) -> lists:flatten(io_lib:format("~s...",[Trunc])) end, Total = TotSucc+TotFail+AllSkip, - A = ["<TD ALIGN=center><FONT SIZE=-1>",Node,"</FONT></TD>\n", - "<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</B></FONT></TD>\n", - "<TD ALIGN=right>",NoOfTests,"</TD>\n"], - B = if BasicHtml -> - ["<TD ALIGN=center><FONT SIZE=-1>",TestNamesTrunc,"</FONT></TD>\n"]; - true -> - ["<TD ALIGN=center TITLE='",TestNames,"'><FONT SIZE=-1> ", - TestNamesTrunc,"</FONT></TD>\n"] - end, - C = ["<TD ALIGN=right>",integer_to_list(Total),"</TD>\n", - "<TD ALIGN=right>",integer_to_list(TotSucc),"</TD>\n", - "<TD ALIGN=right>",TotFailStr,"</TD>\n", - "<TD ALIGN=right>",integer_to_list(AllSkip), - " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n", - "<TD ALIGN=right>",integer_to_list(NotBuilt),"</TD>\n"], + A = xhtml(["<td align=center><font size=\"-1\">",Node, + "</font></td>\n", + "<td align=center><font size=\"-1\"><b>",Label, + "</b></font></td>\n", + "<td align=right>",NoOfTests,"</td>\n"], + ["<td align=center>",Node,"</td>\n", + "<td align=center><b>",Label,"</b></td>\n", + "<td align=right>",NoOfTests,"</td>\n"]), + B = xhtml(["<td align=center title='",TestNames,"'><font size=\"-1\"> ", + TestNamesTrunc,"</font></td>\n"], + ["<td align=center title='",TestNames,"'> ", + TestNamesTrunc,"</td>\n"]), + C = ["<td align=right>",integer_to_list(Total),"</td>\n", + "<td align=right>",integer_to_list(TotSucc),"</td>\n", + "<td align=right>",TotFailStr,"</td>\n", + "<td align=right>",integer_to_list(AllSkip), + " (",UserSkipStr,"/",AutoSkipStr,")</td>\n", + "<td align=right>",integer_to_list(NotBuilt),"</td>\n"], A++B++C; _ -> - ["<TD ALIGN=center><FONT size=-1 color=\"red\">", - "Test data missing or corrupt","</FONT></TD>\n"] + A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">" + "Test data missing or corrupt</font></td>\n", + "<td align=center><font size=\"-1\">?</font></td>\n", + "<td align=right>?</td>\n"], + ["<td align=center><font color=\"red\">" + "Test data missing or corrupt</font></td>\n", + "<td align=center>?</td>\n", + "<td align=right>?</td>\n"]), + B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"], + ["<td align=center>?</td>\n"]), + C = ["<td align=right>?</td>\n", + "<td align=right>?</td>\n", + "<td align=right>?</td>\n", + "<td align=right>?</td>\n", + "<td align=right>?</td>\n"], + A++B++C end, Index = filename:join(Dir,?index_name), - ["<TR>\n" - "<TD><FONT SIZE=-1><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</FONT></TD>\n" - "</TR>\n"]. + [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]), + xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",timestamp(Dir),"</a>", + TotalsStr,"</font></td>\n"], + ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,"</td>\n"]), + "</tr>\n"]. write_totals_file(Name,Label,Logs,Totals) -> AbsName = ?abs(Name), @@ -1482,6 +1582,7 @@ timestamp(Dir) -> %% Creates the top level index file. When == start | refresh. %% A copy of the dir tree under logdir is cached as a result. make_all_suites_index(When) when is_atom(When) -> + put(basic_html, basic_html()), AbsIndexName = ?abs(?index_name), notify_and_lock_file(AbsIndexName), LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext), @@ -1493,6 +1594,7 @@ make_all_suites_index(When) when is_atom(When) -> %% This updates the top level index file using cached data from %% the initial index file creation. make_all_suites_index(NewTestData = {_TestName,DirName}) -> + put(basic_html, basic_html()), %% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...] {AbsIndexName,LogDirData} = ct_util:get_testdata(test_index), @@ -1850,6 +1952,38 @@ last_test([], Latest) -> Latest. %%%----------------------------------------------------------------- +%%% @spec xhtml(HTML, XHTML) -> HTML | XHTML +%%% +%%% @doc +%%% +xhtml(HTML, XHTML) when is_function(HTML), + is_function(XHTML) -> + case get(basic_html) of + true -> HTML(); + _ -> XHTML() + end; +xhtml(HTML, XHTML) -> + case get(basic_html) of + true -> HTML; + _ -> XHTML + end. + +%%%----------------------------------------------------------------- +%%% @spec odd_or_even() -> "odd" | "even" +%%% +%%% @doc +%%% +odd_or_even() -> + case get(odd_or_even) of + even -> + put(odd_or_even, odd), + "even"; + _ -> + put(odd_or_even, even), + "odd" + end. + +%%%----------------------------------------------------------------- %%% @spec basic_html() -> true | false %%% %%% @doc @@ -1861,3 +1995,149 @@ basic_html() -> _ -> false end. + +%%%----------------------------------------------------------------- +%%% @spec locate_default_css_file() -> CSSFile +%%% +%%% @doc +%%% +locate_default_css_file() -> + {ok,CWD} = file:get_cwd(), + CSSFileInCwd = filename:join(CWD, ?css_default), + case filelib:is_file(CSSFileInCwd) of + true -> + CSSFileInCwd; + false -> + CSSResultFile = + case {whereis(?MODULE),self()} of + {Self,Self} -> + %% executed on the ct_logs process + filename:join(get(ct_run_dir), ?css_default); + _ -> + %% executed on other process than ct_logs + {ok,RunDir} = get_log_dir(true), + filename:join(RunDir, ?css_default) + end, + case filelib:is_file(CSSResultFile) of + true -> + CSSResultFile; + false -> + %% last resort, try use css file in CT installation + CTPath = code:lib_dir(common_test), + filename:join(filename:join(CTPath, "priv"), ?css_default) + end + end. + +%%%----------------------------------------------------------------- +%%% @spec make_relative(AbsDir, Cwd) -> RelDir +%%% +%%% @doc Return directory path to File (last element of AbsDir), which +%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs": +%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log" +%%% make_relative("/ldisk/test/trace.log") -> "../trace.log" +%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log" +make_relative(AbsDir) -> + {ok,Cwd} = file:get_cwd(), + make_relative(AbsDir, Cwd). + +make_relative(AbsDir, Cwd) -> + DirTokens = filename:split(AbsDir), + CwdTokens = filename:split(Cwd), + filename:join(make_relative1(DirTokens, CwdTokens)). + +make_relative1([T | DirTs], [T | CwdTs]) -> + make_relative1(DirTs, CwdTs); +make_relative1(Last = [_File], []) -> + Last; +make_relative1(Last = [_File], CwdTs) -> + Ups = ["../" || _ <- CwdTs], + Ups ++ Last; +make_relative1(DirTs, []) -> + DirTs; +make_relative1(DirTs, CwdTs) -> + Ups = ["../" || _ <- CwdTs], + Ups ++ DirTs. + +%%%----------------------------------------------------------------- +%%% @spec get_ts_html_wrapper(TestName, PrintLabel, Cwd) -> {Mode,Header,Footer} +%%% +%%% @doc +%%% +get_ts_html_wrapper(TestName, PrintLabel, Cwd) -> + TestName1 = if is_list(TestName) -> + lists:flatten(TestName); + true -> + lists:flatten(io_lib:format("~p", [TestName])) + end, + Basic = basic_html(), + LabelStr = + if not PrintLabel -> + ""; + true -> + case {Basic,application:get_env(common_test, test_label)} of + {true,{ok,Lbl}} when Lbl =/= undefined -> + "<h1><font color=\"green\">" ++ Lbl ++ "</font></h1>\n"; + {_,{ok,Lbl}} when Lbl =/= undefined -> + "<div class=\"label\">'" ++ Lbl ++ "'</div>\n"; + _ -> + "" + end + end, + CTPath = code:lib_dir(common_test), + {ok,CtLogdir} = get_log_dir(true), + AllRuns = make_relative(filename:join(filename:dirname(CtLogdir), + ?all_runs_name), Cwd), + TestIndex = make_relative(filename:join(filename:dirname(CtLogdir), + ?index_name), Cwd), + case Basic of + true -> + TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"), + Bgr = " background=\"" ++ TileFile ++ "\"", + Copyright = + ["<p><font size=\"-1\">\n", + "Copyright © ", year(), + " <a href=\"http://www.erlang.org\">", + "Open Telecom Platform</a><br>\n", + "Updated: <!date>", current_time(), "<!/date>", + "<br>\n</font></p>\n"], + {basic_html, + ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", + "<html>\n", + "<head><title>", TestName1, "</title>\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "</head>\n", + "<body", Bgr, " bgcolor=\"white\" text=\"black\" ", + "link=\"blue\" vlink=\"purple\" alink=\"red\">\n", + LabelStr, "\n"], + ["<center>\n<br><hr><p>\n", + "<a href=\"", AllRuns, + "\">Test run history\n</a> | ", + "<a href=\"", TestIndex, + "\">Top level test index\n</a>\n</p>\n", + Copyright,"</center>\n</body>\n</html>\n"]}; + _ -> + Copyright = + ["<div class=\"copyright\">", + "Copyright © ", year(), + " <a href=\"http://www.erlang.org\">", + "Open Telecom Platform</a><br />\n", + "Updated: <!date>", current_time(), "<!/date>", + "<br />\n</div>\n"], + CSSFile = xhtml(fun() -> "" end, + fun() -> make_relative(locate_default_css_file(), Cwd) end), + {xhtml, + ["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n", + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n", + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n", + "<head>\n<title>", TestName1, "</title>\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "<link rel=\"stylesheet\" href=\"", CSSFile, "\" type=\"text/css\">", + "</head>\n","<body>\n", + LabelStr, "\n"], + ["<center>\n<br /><hr /><p>\n", + "<a href=\"", AllRuns, + "\">Test run history\n</a> | ", + "<a href=\"", TestIndex, + "\">Top level test index\n</a>\n</p>\n", + Copyright,"</center>\n</body>\n</html>\n"]} + end. diff --git a/lib/compiler/doc/src/make.dep b/lib/compiler/doc/src/make.dep deleted file mode 100644 index f5c097afad..0000000000 --- a/lib/compiler/doc/src/make.dep +++ /dev/null @@ -1,19 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex compile.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl index 6e63c4d0f2..4a9c12dfea 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -146,8 +146,10 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) -> Essentials0 = [AtomChunk,CodeChunk,StringChunk,ImportChunk, ExpChunk,LambdaChunk,LiteralChunk], - Essentials = [iolist_to_binary(C) || C <- Essentials0], - {Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, Essentials), + Essentials1 = [iolist_to_binary(C) || C <- Essentials0], + MD5 = module_md5(Essentials1), + Essentials = finalize_fun_table(Essentials1, MD5), + {Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, MD5), AttrChunk = chunk(<<"Attr">>, Attributes), CompileChunk = chunk(<<"CInf">>, Compile), @@ -166,6 +168,24 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) -> end, build_form(<<"BEAM">>, Chunks). +%% finalize_fun_table(Essentials, MD5) -> FinalizedEssentials +%% Update the 'old_uniq' field in the entry for each fun in the +%% 'FunT' chunk. We'll use part of the MD5 for the module as a +%% unique value. + +finalize_fun_table(Essentials, MD5) -> + [finalize_fun_table_1(E, MD5) || E <- Essentials]. + +finalize_fun_table_1(<<"FunT",Keep:8/binary,Table0/binary>>, MD5) -> + <<Uniq:27,_:101/bits>> = MD5, + Table = finalize_fun_table_2(Table0, Uniq, <<>>), + <<"FunT",Keep/binary,Table/binary>>; +finalize_fun_table_1(Chunk, _) -> Chunk. + +finalize_fun_table_2(<<Keep:20/binary,0:32,T/binary>>, Uniq, Acc) -> + finalize_fun_table_2(T, Uniq, <<Acc/binary,Keep/binary,Uniq:32>>); +finalize_fun_table_2(<<>>, _, Acc) -> Acc. + %% Build an IFF form. build_form(Id, Chunks0) when byte_size(Id) =:= 4, is_list(Chunks0) -> @@ -202,7 +222,7 @@ flatten_exports(Exps) -> flatten_imports(Imps) -> list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)). -build_attributes(Opts, SourceFile, Attr, Essentials) -> +build_attributes(Opts, SourceFile, Attr, MD5) -> Misc = case member(slim, Opts) of false -> {{Y,Mo,D},{H,Mi,S}} = erlang:universaltime(), @@ -210,7 +230,7 @@ build_attributes(Opts, SourceFile, Attr, Essentials) -> true -> [] end, Compile = [{options,Opts},{version,?COMPILER_VSN}|Misc], - {term_to_binary(calc_vsn(Attr, Essentials)),term_to_binary(Compile)}. + {term_to_binary(set_vsn_attribute(Attr, MD5)),term_to_binary(Compile)}. build_line_table(Dict) -> {NumLineInstrs,NumFnames0,Fnames0,NumLines,Lines0} = @@ -243,32 +263,30 @@ encode_line_items([], _) -> []. %% We'll not change an existing 'vsn' attribute. %% -calc_vsn(Attr, Essentials0) -> +set_vsn_attribute(Attr, MD5) -> case keymember(vsn, 1, Attr) of true -> Attr; false -> - Essentials = filter_essentials(Essentials0), - <<Number:128>> = erlang:md5(Essentials), + <<Number:128>> = MD5, [{vsn,[Number]}|Attr] end. +module_md5(Essentials0) -> + Essentials = filter_essentials(Essentials0), + erlang:md5(Essentials). + %% filter_essentials([Chunk]) -> [Chunk'] %% Filter essentials so that we obtain the same MD5 as code:module_md5/1 and -%% beam_lib:md5/1 would calculate for this module. +%% beam_lib:md5/1 would calculate for this module. Note that at this +%% point, the 'old_uniq' entry for each fun in the 'FunT' chunk is zeroed, +%% so there is no need to go through the 'FunT' chunk. -filter_essentials([<<"FunT",_Sz:4/binary,Entries:4/binary,Table0/binary>>|T]) -> - Table = filter_funtab(Table0, <<0:32>>), - [Entries,Table|filter_essentials(T)]; filter_essentials([<<_Tag:4/binary,Sz:32,Data:Sz/binary,_Padding/binary>>|T]) -> [Data|filter_essentials(T)]; filter_essentials([<<>>|T]) -> filter_essentials(T); filter_essentials([]) -> []. -filter_funtab(<<Important:20/binary,_OldUniq:4/binary,T/binary>>, Zero) -> - [Important,Zero|filter_funtab(T, Zero)]; -filter_funtab(<<>>, _) -> []. - bif_type(fnegate, 1) -> {op,fnegate}; bif_type(fadd, 2) -> {op,fadd}; bif_type(fsub, 2) -> {op,fsub}; @@ -310,8 +328,8 @@ make_op({test,Cond,Fail,Ops}, Dict) when is_list(Ops) -> encode_op(Cond, [Fail|Ops], Dict); make_op({test,Cond,Fail,Live,[Op|Ops],Dst}, Dict) when is_list(Ops) -> encode_op(Cond, [Fail,Op,Live|Ops++[Dst]], Dict); -make_op({make_fun2,{f,Lbl},Index,OldUniq,NumFree}, Dict0) -> - {Fun,Dict} = beam_dict:lambda(Lbl, Index, OldUniq, NumFree, Dict0), +make_op({make_fun2,{f,Lbl},_Index,_OldUniq,NumFree}, Dict0) -> + {Fun,Dict} = beam_dict:lambda(Lbl, NumFree, Dict0), make_op({make_fun2,Fun}, Dict); make_op({kill,Y}, Dict) -> make_op({init,Y}, Dict); diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl index ee76623976..531968b3c8 100644 --- a/lib/compiler/src/beam_dict.erl +++ b/lib/compiler/src/beam_dict.erl @@ -22,7 +22,7 @@ -export([new/0,opcode/2,highest_opcode/1, atom/2,local/4,export/4,import/4, - string/2,lambda/5,literal/2,line/2,fname/2, + string/2,lambda/3,literal/2,line/2,fname/2, atom_table/1,local_table/1,export_table/1,import_table/1, string_table/1,lambda_table/1,literal_table/1, line_table/1]). @@ -133,13 +133,18 @@ string(Str, Dict) when is_list(Str) -> {NextOffset-Offset,Dict} end. -%% Returns the index for a funentry (adding it to the table if necessary). -%% lambda(Lbl, Index, Uniq, NumFree, Dict) -> {Index,Dict'} --spec lambda(label(), non_neg_integer(), integer(), non_neg_integer(), bdict()) -> +%% Returns the index for a fun entry. +%% lambda(Lbl, NumFree, Dict) -> {Index,Dict'} +-spec lambda(label(), non_neg_integer(), bdict()) -> {non_neg_integer(), bdict()}. -lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) -> +lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) -> OldIndex = length(Lambdas0), + %% Set Index the same as OldIndex. + Index = OldIndex, + %% Initialize OldUniq to 0. It will be set to an unique value + %% based on the MD5 checksum of the BEAM code for the module. + OldUniq = 0, Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0], {OldIndex,Dict#asm{lambdas=Lambdas}}. diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index 7fdb8d072a..0c51251f1b 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -168,6 +168,8 @@ simplify_float_1([{set,[D0],[A,B],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0, Ts0, simplify_float_1([{set,_,_,{'catch',_}}=I|Is]=Is0, _Ts, Rs0, Acc0) -> Acc = flush_all(Rs0, Is0, Acc0), simplify_float_1(Is, tdb_new(), Rs0, [I|Acc]); +simplify_float_1([{set,_,_,{line,_}}=I|Is], Ts, Rs, Acc) -> + simplify_float_1(Is, Ts, Rs, [I|Acc]); simplify_float_1([I|Is]=Is0, Ts0, Rs0, Acc0) -> Ts = update(I, Ts0), {Rs,Acc} = flush(Rs0, Is0, Acc0), diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl index 0fa1fea09f..ba9cde1de0 100644 --- a/lib/compiler/src/sys_pre_expand.erl +++ b/lib/compiler/src/sys_pre_expand.erl @@ -31,8 +31,6 @@ -import(ordsets, [from_list/1,add_element/2,union/2]). -import(lists, [member/2,foldl/3,foldr/3]). --compile({nowarn_deprecated_function, {erlang,hash,2}}). - -include("../include/erl_bits.hrl"). -record(expand, {module=[], %Module name @@ -49,7 +47,6 @@ func=[], %Current function arity=[], %Arity for current function fcount=0, %Local fun count - fun_index=0, %Global index for funs bitdefault, bittypes }). @@ -538,32 +535,34 @@ lc_tq(_Line, [], St0) -> %% Transform an "explicit" fun {'fun', Line, {clauses, Cs}} into an %% extended form {'fun', Line, {clauses, Cs}, Info}, unless it is the %% name of a BIF (erl_lint has checked that it is not an import). -%% Process the body sequence directly to get the new and used variables. %% "Implicit" funs {'fun', Line, {function, F, A}} are not changed. fun_tq(Lf, {function,F,A}=Function, St0) -> - {As,St1} = new_vars(A, Lf, St0), - Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}], case erl_internal:bif(F, A) of true -> + {As,St1} = new_vars(A, Lf, St0), + Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}], fun_tq(Lf, {clauses,Cs}, St1); false -> - Index = St0#expand.fun_index, - Uniq = erlang:hash(Cs, (1 bsl 27)-1), - {Fname,St2} = new_fun_name(St1), - {{'fun',Lf,Function,{Index,Uniq,Fname}}, - St2#expand{fun_index=Index+1}} + {Fname,St1} = new_fun_name(St0), + Index = Uniq = 0, + {{'fun',Lf,Function,{Index,Uniq,Fname}},St1} end; -fun_tq(L, {function,M,F,A}, St) -> - {{call,L,{remote,L,{atom,L,erlang},{atom,L,make_fun}}, - [{atom,L,M},{atom,L,F},{integer,L,A}]},St}; +fun_tq(L, {function,M,F,A}, St) when is_atom(M), is_atom(F), is_integer(A) -> + %% This is the old format for external funs, generated by a pre-R15 + %% compiler. That means that a tool, such as the debugger or xref, + %% directly invoked this module with the abstract code from a + %% pre-R15 BEAM file. Be helpful, and translate it to the new format. + fun_tq(L, {function,{atom,L,M},{atom,L,F},{integer,L,A}}, St); +fun_tq(Lf, {function,_,_,_}=ExtFun, St) -> + {{'fun',Lf,ExtFun},St}; fun_tq(Lf, {clauses,Cs0}, St0) -> - Uniq = erlang:hash(Cs0, (1 bsl 27)-1), {Cs1,St1} = fun_clauses(Cs0, St0), - Index = St1#expand.fun_index, {Fname,St2} = new_fun_name(St1), - {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}}, - St2#expand{fun_index=Index+1}}. + %% Set dummy values for Index and Uniq -- the real values will + %% be assigned by beam_asm. + Index = Uniq = 0, + {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}},St2}. fun_clauses([{clause,L,H0,G0,B0}|Cs0], St0) -> {H,St1} = head(H0, St0), diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 6f3590b156..6885405ae0 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -573,6 +573,13 @@ expr({'catch',L,E0}, St0) -> expr({'fun',L,{function,F,A},{_,_,_}=Id}, St) -> Lanno = lineno_anno(L, St), {#c_var{anno=Lanno++[{id,Id}],name={F,A}},[],St}; +expr({'fun',L,{function,M,F,A}}, St0) -> + {As,Aps,St1} = safe_list([M,F,A], St0), + Lanno = lineno_anno(L, St1), + {#icall{anno=#a{anno=Lanno}, + module=#c_literal{val=erlang}, + name=#c_literal{val=make_fun}, + args=As},Aps,St1}; expr({'fun',L,{clauses,Cs},Id}, St) -> fun_tq(Id, Cs, L, St); expr({call,L,{remote,_,M,F},As0}, #core{wanted=Wanted}=St0) -> diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 4e06b464a4..47e5e49a76 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -84,8 +84,6 @@ keymember/3,keyfind/3]). -import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]). --compile({nowarn_deprecated_function, {erlang,hash,2}}). - -include("core_parse.hrl"). -include("v3_kernel.hrl"). @@ -1658,31 +1656,31 @@ uexpr(#k_catch{anno=A,body=B0}, {break,Rs0}, St0) -> {Ns,St3} = new_vars(1 - length(Rs0), St2), Rs1 = Rs0 ++ Ns, {#k_catch{anno=#k{us=Bu,ns=lit_list_vars(Rs1),a=A},body=B1,ret=Rs1},Bu,St3}; -uexpr(#ifun{anno=A,vars=Vs,body=B0}=IFun, {break,Rs}, St0) -> +uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) -> {B1,Bu,St1} = ubody(B0, return, St0), %Return out of new function Ns = lit_list_vars(Vs), Free = subtract(Bu, Ns), %Free variables in fun Fvs = make_vars(Free), Arity = length(Vs) + length(Free), - {{Index,Uniq,Fname}, St3} = + {Fname,St} = case lists:keyfind(id, 1, A) of - {id,Id} -> - {Id, St1}; + {id,{_,_,Fname0}} -> + {Fname0,St1}; false -> - %% No id annotation. Must invent one. - I = St1#kern.fcount, - U = erlang:hash(IFun, (1 bsl 27)-1), - {N, St2} = new_fun_name(St1), - {{I,U,N}, St2} + %% No id annotation. Must invent a fun name. + new_fun_name(St1) end, Fun = #k_fdef{anno=#k{us=[],ns=[],a=A},func=Fname,arity=Arity, vars=Vs ++ Fvs,body=B1}, + %% Set dummy values for Index and Uniq -- the real values will + %% be assigned by beam_asm. + Index = Uniq = 0, {#k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A}, op=#k_internal{name=make_fun,arity=length(Free)+3}, args=[#k_atom{val=Fname},#k_int{val=Arity}, #k_int{val=Index},#k_int{val=Uniq}|Fvs], ret=Rs}, - Free,add_local_function(Fun, St3)}; + Free,add_local_function(Fun, St)}; uexpr(Lit, {break,Rs}, St) -> %% Transform literals to puts here. %%ok = io:fwrite("uexpr ~w:~p~n", [?LINE,Lit]), diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl index 368a5815bf..6067ee8e06 100644 --- a/lib/compiler/test/fun_SUITE.erl +++ b/lib/compiler/test/fun_SUITE.erl @@ -20,7 +20,11 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1]). + test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1, + external/1]). + +%% Internal export. +-export([call_me/1]). -include_lib("test_server/include/test_server.hrl"). @@ -28,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [test1, overwritten_fun, otp_7202, bif_fun]. + [test1,overwritten_fun,otp_7202,bif_fun,external]. groups() -> []. @@ -45,7 +49,6 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - %%% The help functions below are copied from emulator:bs_construct_SUITE. -define(T(B, L), {B, ??B, L}). @@ -152,4 +155,47 @@ bif_fun(Config) when is_list(Config) -> ?line F = fun abs/1, ?line 5 = F(-5), ok. + +-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)). +-define(APPLY2(M, F, A), + (fun(Map) -> + Id = fun(I) -> I end, + List = [x,y], + List = Map(Id, List), + {type,external} = erlang:fun_info(Map, type) + end)(fun M:F/A)). +external(Config) when is_list(Config) -> + Mod = id(?MODULE), + Func = id(call_me), + Arity = id(1), + + ?APPLY(?MODULE, call_me, 1), + ?APPLY(?MODULE, call_me, Arity), + ?APPLY(?MODULE, Func, 1), + ?APPLY(?MODULE, Func, Arity), + ?APPLY(Mod, call_me, 1), + ?APPLY(Mod, call_me, Arity), + ?APPLY(Mod, Func, 1), + ?APPLY(Mod, Func, Arity), + + ListsMod = id(lists), + ListsMap = id(map), + ListsArity = id(2), + + ?APPLY2(lists, map, 2), + ?APPLY2(lists, map, ListsArity), + ?APPLY2(lists, ListsMap, 2), + ?APPLY2(lists, ListsMap, ListsArity), + ?APPLY2(ListsMod, map, 2), + ?APPLY2(ListsMod, map, ListsArity), + ?APPLY2(ListsMod, ListsMap, 2), + ?APPLY2(ListsMod, ListsMap, ListsArity), + + ok. + +call_me(I) -> + {ok,I}. + +id(I) -> + I. diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl index 9a317b5762..3d02adaf52 100644 --- a/lib/compiler/test/pmod_SUITE.erl +++ b/lib/compiler/test/pmod_SUITE.erl @@ -96,6 +96,10 @@ basic_1(Config, Opts) -> ?line error = Prop4:bar_bar({s,a,b}), ?line error = Prop4:bar_bar([]), + %% Call from a fun. + Fun = fun(Arg) -> Prop4:bar(Arg) end, + ?line ok = Fun({s,0}), + ok. otp_8447(Config) when is_list(Config) -> diff --git a/lib/cosEvent/doc/src/Makefile b/lib/cosEvent/doc/src/Makefile index 4b76a64b7d..db2f7e6da5 100644 --- a/lib/cosEvent/doc/src/Makefile +++ b/lib/cosEvent/doc/src/Makefile @@ -26,13 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include ../../vsn.mk VSN=$(COSEVENT_VSN) APPLICATION=cosEvent -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif # ---------------------------------------------------- # Release directory specification @@ -98,32 +91,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -136,8 +107,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -153,31 +122,6 @@ clean clean_docs: rm -f errs core *~ rm -f $(JD_HTML) $(JD_PACK) -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -192,8 +136,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -204,30 +146,4 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif - release_spec: - diff --git a/lib/cosEvent/doc/src/make.dep b/lib/cosEvent/doc/src/make.dep deleted file mode 100644 index b8a95c2d58..0000000000 --- a/lib/cosEvent/doc/src/make.dep +++ /dev/null @@ -1,34 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosEventChannelAdmin.tex CosEventChannelAdmin_ConsumerAdmin.tex \ - CosEventChannelAdmin_EventChannel.tex CosEventChannelAdmin_ProxyPullConsumer.tex \ - CosEventChannelAdmin_ProxyPullSupplier.tex \ - CosEventChannelAdmin_ProxyPushConsumer.tex \ - CosEventChannelAdmin_ProxyPushSupplier.tex \ - CosEventChannelAdmin_SupplierAdmin.tex book.tex \ - ch_contents.tex ch_event_service.tex ch_introduction.tex \ - cosEventApp.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -CosEventChannelAdmin.tex: ../../src/CosEventChannelAdmin.idl - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: e_s_components.ps e_s_models.ps - diff --git a/lib/cosEventDomain/doc/src/Makefile b/lib/cosEventDomain/doc/src/Makefile index 6a0d3c353a..b2cdef278a 100644 --- a/lib/cosEventDomain/doc/src/Makefile +++ b/lib/cosEventDomain/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(COSEVENTDOMAIN_VSN) APPLICATION=cosEventDomain # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -93,33 +85,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -132,8 +101,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -149,32 +116,6 @@ clean clean_docs: rm -f errs core *~ rm -f $(JD_HTML) $(JD_PACK) -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -189,9 +130,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk - -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -201,30 +139,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosEventDomain/doc/src/make.dep b/lib/cosEventDomain/doc/src/make.dep deleted file mode 100644 index 2f3f1ae53d..0000000000 --- a/lib/cosEventDomain/doc/src/make.dep +++ /dev/null @@ -1,23 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosEventDomainAdmin.tex CosEventDomainAdmin_EventDomain.tex \ - CosEventDomainAdmin_EventDomainFactory.tex \ - book.tex ch_QoS.tex ch_contents.tex ch_event_domain_service.tex \ - ch_introduction.tex cosEventDomainApp.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/cosFileTransfer/doc/src/Makefile b/lib/cosFileTransfer/doc/src/Makefile index 2286db43ff..e62738daba 100644 --- a/lib/cosFileTransfer/doc/src/Makefile +++ b/lib/cosFileTransfer/doc/src/Makefile @@ -26,14 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include ../../vsn.mk VSN=$(COSFILETRANSFER_VSN) APPLICATION=cosFileTransfer -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - # ---------------------------------------------------- # Release directory specification @@ -97,33 +89,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -136,8 +105,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -152,32 +119,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -192,9 +133,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk - -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -204,30 +142,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosFileTransfer/doc/src/make.dep b/lib/cosFileTransfer/doc/src/make.dep deleted file mode 100644 index 3be0c185c3..0000000000 --- a/lib/cosFileTransfer/doc/src/make.dep +++ /dev/null @@ -1,30 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosFileTransfer_Directory.tex CosFileTransfer_File.tex \ - CosFileTransfer_FileIterator.tex CosFileTransfer_FileTransferSession.tex \ - CosFileTransfer_VirtualFileSystem.tex book.tex \ - ch_contents.tex ch_example.tex ch_install.tex \ - ch_introduction.tex ch_system.tex cosFileTransferApp.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosFileTransfer.ps - diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile index bfdd2f1f8c..2ead9aba7b 100644 --- a/lib/cosNotification/doc/src/Makefile +++ b/lib/cosNotification/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(COSNOTIFICATION_VSN) APPLICATION=cosNotification # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -122,33 +114,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -161,8 +130,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -177,32 +144,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -217,8 +158,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -228,30 +167,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosNotification/doc/src/make.dep b/lib/cosNotification/doc/src/make.dep deleted file mode 100644 index 031a2b3e98..0000000000 --- a/lib/cosNotification/doc/src/make.dep +++ /dev/null @@ -1,48 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosNotification.tex CosNotification_AdminPropertiesAdmin.tex \ - CosNotification_QoSAdmin.tex CosNotifyChannelAdmin_ConsumerAdmin.tex \ - CosNotifyChannelAdmin_EventChannel.tex CosNotifyChannelAdmin_EventChannelFactory.tex \ - CosNotifyChannelAdmin_ProxyConsumer.tex CosNotifyChannelAdmin_ProxyPullConsumer.tex \ - CosNotifyChannelAdmin_ProxyPullSupplier.tex \ - CosNotifyChannelAdmin_ProxyPushConsumer.tex \ - CosNotifyChannelAdmin_ProxyPushSupplier.tex \ - CosNotifyChannelAdmin_ProxySupplier.tex CosNotifyChannelAdmin_SequenceProxyPullConsumer.tex \ - CosNotifyChannelAdmin_SequenceProxyPullSupplier.tex \ - CosNotifyChannelAdmin_SequenceProxyPushConsumer.tex \ - CosNotifyChannelAdmin_SequenceProxyPushSupplier.tex \ - CosNotifyChannelAdmin_StructuredProxyPullConsumer.tex \ - CosNotifyChannelAdmin_StructuredProxyPullSupplier.tex \ - CosNotifyChannelAdmin_StructuredProxyPushConsumer.tex \ - CosNotifyChannelAdmin_StructuredProxyPushSupplier.tex \ - CosNotifyChannelAdmin_SupplierAdmin.tex CosNotifyComm_NotifyPublish.tex \ - CosNotifyComm_NotifySubscribe.tex CosNotifyFilter_Filter.tex \ - CosNotifyFilter_FilterAdmin.tex CosNotifyFilter_FilterFactory.tex \ - CosNotifyFilter_MappingFilter.tex book.tex \ - ch_BNF.tex ch_QoS.tex ch_contents.tex ch_example.tex \ - ch_install.tex ch_introduction.tex ch_system.tex \ - cosNotificationApp.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: eventstructure.ps - -book.dvi: notificationFlow.ps - diff --git a/lib/cosProperty/doc/src/Makefile b/lib/cosProperty/doc/src/Makefile index baf995d35e..d4c89ff44f 100644 --- a/lib/cosProperty/doc/src/Makefile +++ b/lib/cosProperty/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(COSPROPERTY_VSN) APPLICATION=cosProperty # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -99,35 +91,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) MAN6_FILES = $(XML_REF6_FILES:%.xml=$(MAN6DIR)/%.6) - -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_REF6_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -140,8 +107,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -156,42 +121,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -tex_users_guide: $(TEX_FILES_USERS_GUIDE) -tex_ref_man: $(TEX_FILES_REF_MAN) -tex: tex_users_guide tex_ref_man $(TEX_FILES_BOOK) - -$(DOCDIR)/latexlog: $(BOOK_FILES:%.xml=%.dvi) - -fgrep -i "latex warning" $(BOOK_FILES:%.xml=%.log) >$(DOCDIR)/latexlog - -clean_tex: - -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - -clean: - rm -f ../html/* $(MAN3_FILES) $(MAN6_FILES) $(TEX_FILES_USERS_GUIDE) - rm -f *xmls_output *xmls_errs - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) $(MAN6_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -206,8 +135,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -217,30 +144,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosProperty/doc/src/make.dep b/lib/cosProperty/doc/src/make.dep deleted file mode 100644 index 383af54244..0000000000 --- a/lib/cosProperty/doc/src/make.dep +++ /dev/null @@ -1,26 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosPropertyService_PropertiesIterator.tex \ - CosPropertyService_PropertyNamesIterator.tex \ - CosPropertyService_PropertySet.tex CosPropertyService_PropertySetDef.tex \ - CosPropertyService_PropertySetDefFactory.tex \ - CosPropertyService_PropertySetFactory.tex \ - book.tex ch_contents.tex ch_example.tex ch_install.tex \ - ch_introduction.tex cosProperty.tex part.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/cosTime/doc/src/Makefile b/lib/cosTime/doc/src/Makefile index 83abc5e7c2..af418896aa 100644 --- a/lib/cosTime/doc/src/Makefile +++ b/lib/cosTime/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(COSTIME_VSN) APPLICATION=cosTime # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -93,33 +85,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -132,8 +101,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -148,32 +115,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -188,8 +129,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -199,30 +138,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosTime/doc/src/make.dep b/lib/cosTime/doc/src/make.dep deleted file mode 100644 index 69a584ab95..0000000000 --- a/lib/cosTime/doc/src/make.dep +++ /dev/null @@ -1,22 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosTime_TIO.tex CosTime_TimeService.tex CosTime_UTO.tex \ - CosTimerEvent_TimerEventHandler.tex CosTimerEvent_TimerEventService.tex \ - book.tex ch_contents.tex ch_example.tex ch_install.tex \ - ch_introduction.tex cosTime.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/cosTransactions/doc/src/Makefile b/lib/cosTransactions/doc/src/Makefile index 1af9ed24b7..7d959cbc8f 100644 --- a/lib/cosTransactions/doc/src/Makefile +++ b/lib/cosTransactions/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(COSTRANSACTIONS_VSN) APPLICATION=cosTransactions # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -97,33 +89,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf - -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -136,8 +105,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -152,32 +119,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -192,8 +133,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -203,30 +142,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/cosTransactions/doc/src/make.dep b/lib/cosTransactions/doc/src/make.dep deleted file mode 100644 index bd45aea286..0000000000 --- a/lib/cosTransactions/doc/src/make.dep +++ /dev/null @@ -1,27 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosTransactions_Control.tex CosTransactions_Coordinator.tex \ - CosTransactions_RecoveryCoordinator.tex CosTransactions_Resource.tex \ - CosTransactions_SubtransactionAwareResource.tex \ - CosTransactions_Terminator.tex CosTransactions_TransactionFactory.tex \ - book.tex ch_contents.tex ch_example.tex ch_install.tex \ - ch_introduction.tex ch_skeletons.tex cosTransactions.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -ch_example.tex: ../../../../system/doc/definitions/term.defs - diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 10fe333d18..802c1991de 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -154,7 +154,7 @@ static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -234,7 +234,7 @@ static ErlNifFunc nif_funcs[] = { {"rc4_encrypt", 2, rc4_encrypt}, {"rc4_set_key", 1, rc4_set_key}, {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, - {"rc2_40_cbc_crypt", 4, rc2_40_cbc_crypt}, + {"rc2_cbc_crypt", 4, rc2_cbc_crypt}, {"rsa_sign_nif", 3, rsa_sign_nif}, {"dss_sign_nif", 3, dss_sign_nif}, {"rsa_public_crypt", 4, rsa_public_crypt}, @@ -1237,30 +1237,31 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N return enif_make_tuple2(env,new_state,new_data); } -static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key,IVec,Data,IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; RC2_KEY rc2_key; ERL_NIF_TERM ret; - + unsigned char iv_copy[8]; + if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || key_bin.size != 5 + || (key_bin.size != 5 && key_bin.size != 8 && key_bin.size != 16) || !enif_inspect_binary(env, argv[1], &ivec_bin) || ivec_bin.size != 8 - || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) { - + || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) + || data_bin.size % 8 != 0) { return enif_make_badarg(env); } - - RC2_set_key(&rc2_key, 5, key_bin.data, 40); + + RC2_set_key(&rc2_key, key_bin.size, key_bin.data, key_bin.size*8); + memcpy(iv_copy, ivec_bin.data, 8); RC2_cbc_encrypt(data_bin.data, - enif_make_new_binary(env, data_bin.size, &ret), + enif_make_new_binary(env, data_bin.size, &ret), data_bin.size, &rc2_key, - ivec_bin.data, + iv_copy, (argv[3] == atom_true)); - return ret; -} +} static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type,Data,Key=[E,N,D]) */ diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 824be09438..48243fd693 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -334,14 +334,16 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </func> <func> <name>sha_mac(Key, Data) -> Mac</name> + <name>sha_mac(Key, Data, MacLength) -> Mac</name> <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> <type> <v>Key = Data = iolist() | binary()</v> <v>Mac = binary()</v> + <v>MacLenength = integer() =< 20 </v> </type> <desc> <p>Computes an <c>SHA MAC</c> message authentification code - from <c>Key</c> and <c>Data</c>, where the length of the Mac + from <c>Key</c> and <c>Data</c>, where the default length of the Mac is 160 bits (20 bytes).</p> </desc> </func> @@ -1046,6 +1048,30 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </func> <func> + <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name> + <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>Ivec = Cipher = binary()</v> + </type> + <desc> + <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p> + </desc> + </func> + + <func> + <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name> + <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>Ivec = Cipher = binary()</v> + </type> + <desc> + <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p> + </desc> + </func> + + <func> <name>rc4_encrypt(Key, Data) -> Result</name> <fsummary>Encrypt data using RC4</fsummary> <type> diff --git a/lib/crypto/doc/src/make.dep b/lib/crypto/doc/src/make.dep deleted file mode 100644 index 73b090bbb6..0000000000 --- a/lib/crypto/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex crypto.tex crypto_app.tex licenses.tex \ - ref_man.tex usersguide.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index e3b921f9fa..0714cb686d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -27,7 +27,7 @@ -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). %-export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). %-export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). --export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac_96/2]). +-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). @@ -42,7 +42,7 @@ -export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]). -export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). --export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). +-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). -export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). -export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). @@ -83,7 +83,7 @@ dss_verify,dss_sign, rsa_verify,rsa_sign, rsa_public_encrypt,rsa_private_decrypt, - rsa_private_encrypt,rsa_public_decrypt, + rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, aes_cbc_128_encrypt, aes_cbc_128_decrypt, exor, @@ -91,7 +91,7 @@ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, %% idea_cbc_encrypt, idea_cbc_decrypt, aes_cbc_256_encrypt, aes_cbc_256_decrypt, - aes_ctr_encrypt, aes_ctr_decrypt, + aes_ctr_encrypt, aes_ctr_decrypt, aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). @@ -260,6 +260,9 @@ md5_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. sha_mac(Key, Data) -> sha_mac_n(Key,Data,20). +sha_mac(Key, Data, Size) -> + sha_mac_n(Key, Data, Size). + sha_mac_96(Key, Data) -> sha_mac_n(Key,Data,12). @@ -689,16 +692,25 @@ rc4_encrypt(_Key, _Data) -> ?nif_stub. rc4_set_key(_Key) -> ?nif_stub. rc4_encrypt_with_state(_State, _Data) -> ?nif_stub. + +%% RC2 block cipher + +rc2_cbc_encrypt(Key, IVec, Data) -> + rc2_cbc_crypt(Key,IVec,Data,true). + +rc2_cbc_decrypt(Key, IVec, Data) -> + rc2_cbc_crypt(Key,IVec,Data,false). + +rc2_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. + %% -%% RC2 - 40 bits block cipher +%% RC2 - 40 bits block cipher - Backwards compatibility not documented. %% -rc2_40_cbc_encrypt(Key, IVec, Data) -> - rc2_40_cbc_crypt(Key,IVec,Data,true). - -rc2_40_cbc_decrypt(Key, IVec, Data) -> - rc2_40_cbc_crypt(Key,IVec,Data,false). +rc2_40_cbc_encrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> + rc2_cbc_crypt(Key,IVec,Data,true). -rc2_40_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. +rc2_40_cbc_decrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> + rc2_cbc_crypt(Key,IVec,Data,false). %% %% DH Diffie-Hellman functions diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 53b4c2a7e1..86acdc27df 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -49,6 +49,7 @@ des_ecb/1, des3_cbc/1, des3_cfb/1, + rc2_cbc/1, aes_cfb/1, aes_cbc/1, aes_cbc_iter/1, @@ -79,8 +80,10 @@ all() -> md5_mac_io, sha, sha_update, hmac_update_sha, hmac_update_sha_n, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, %% sha256, sha256_update, sha512,sha512_update, - des_cbc, des_cfb, des3_cbc, des3_cfb, aes_cfb, aes_cbc, + des_cbc, des_cfb, des3_cbc, des3_cfb, rc2_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_cfb_iter, des_ecb, + des_cbc, rc2_cbc, aes_cfb, aes_cbc, + aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, @@ -347,7 +350,7 @@ hmac_update_md5(Config) when is_list(Config) -> Key2 = "A fine speach by a fine man!", ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.", ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.", - ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.", + ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.", ?line CtxA = crypto:hmac_init(md5, Key2), ?line CtxB = crypto:hmac_update(CtxA, Long1), ?line CtxC = crypto:hmac_update(CtxB, Long2), @@ -604,6 +607,21 @@ des_ecb(Config) when is_list(Config) -> ?line m(Cipher5, <<"he time ">>), ?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")), ?line m(Cipher6, <<"for all ">>). +%% +%% +rc2_cbc(doc) -> + "Encrypt and decrypt according to RC2 CBC and check the result. " + "Example stripped out from public_key application test"; +rc2_cbc(Config) when is_list(Config) -> + + Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>, + IV = <<72,91,135,182,25,42,35,210>>, + + Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>, + Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>, + + Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher), + Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text). %% %% diff --git a/lib/debugger/doc/src/make.dep b/lib/debugger/doc/src/make.dep deleted file mode 100644 index c11fd3c21c..0000000000 --- a/lib/debugger/doc/src/make.dep +++ /dev/null @@ -1,29 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex debugger.tex debugger_chapter.tex \ - i.tex int.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: part.xml ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: images/attach.ps images/cond_break_dialog.ps \ - images/function_break_dialog.ps images/interpret.ps \ - images/line_break_dialog.ps images/monitor.ps \ - images/view.ps - diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl index df725ed9e5..2e88c35741 100644 --- a/lib/debugger/src/dbg_ieval.erl +++ b/lib/debugger/src/dbg_ieval.erl @@ -768,6 +768,21 @@ expr({make_fun,Line,Name,Cs}, Bs, #ieval{module=Module}=Ieval) -> end, {value,Fun,Bs}; +%% Construct an external fun. +expr({make_ext_fun,Line,MFA0}, Bs0, Ieval0) -> + {[M,F,A],Bs} = eval_list(MFA0, Bs0, Ieval0), + try erlang:make_fun(M, F, A) of + Value -> + {value,Value,Bs} + catch + error:badarg -> + Ieval1 = Ieval0#ieval{line=Line}, + Ieval2 = dbg_istk:push(Bs0, Ieval1, false), + Ieval = Ieval2#ieval{module=erlang,function=make_fun, + arguments=[M,F,A],line=-1}, + exception(error, badarg, Bs, Ieval, true) + end; + %% Common test adaptation expr({call_remote,0,ct_line,line,As0,Lc}, Bs0, Ieval0) -> {As,_Bs} = eval_list(As0, Bs0, Ieval0), diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl index ce5631e45f..3c95ef8068 100644 --- a/lib/debugger/src/dbg_iload.erl +++ b/lib/debugger/src/dbg_iload.erl @@ -369,6 +369,14 @@ expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) -> As = new_vars(A, Line), Cs = [{clause,Line,As,[],[{local_call,Line,F,As,true}]}], {make_fun,Line,Name,Cs}; +expr({'fun',Line,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc) + when 0 =< A, A =< 255 -> + %% New format in R15 for fun M:F/A (literal values). + {value,Line,erlang:make_fun(M, F, A)}; +expr({'fun',Line,{function,M,F,A}}, _Lc) -> + %% New format in R15 for fun M:F/A (one or more variables). + MFA = expr_list([M,F,A]), + {make_ext_fun,Line,MFA}; expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,self}},[]}, _Lc) -> {dbg,Line,self,[]}; expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,get_stacktrace}},[]}, _Lc) -> diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl index 4039bf785f..abbec158b0 100644 --- a/lib/debugger/src/dbg_ui_break_win.erl +++ b/lib/debugger/src/dbg_ui_break_win.erl @@ -81,12 +81,12 @@ create_win(GS, {X, Y}, function, Mod, _Line) -> {pack_x, 2}, {pack_y, 3}, {selectmode, multiple}]), - %% Add Ok and Cancel buttons - {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30), + %% Add OK and Cancel buttons + {Wbtn, Hbtn} = dbg_ui_win:min_size(["OK","Cancel"], 70, 30), Bot = gs:frame(Frm, [{pack_x, {1, 3}}, {pack_y, 4}]), - Ok = gs:button(Bot, [{x, Pad}, {y, Pad}, + OK = gs:button(Bot, [{x, Pad}, {y, Pad}, {width, Wbtn}, {height, Hbtn}, - {label, {text,"Ok"}}, {font, Font}]), + {label, {text,"OK"}}, {font, Font}]), Cancel = gs:button(Bot, [{x, W-Pad-Wbtn}, {y, Pad}, {width, Wbtn}, {height, Hbtn}, {label, {text,"Cancel"}}, {font, Font}]), @@ -95,7 +95,7 @@ create_win(GS, {X, Y}, function, Mod, _Line) -> gs:config(Win, [{width, Wfrm}, {height, Hfrm}, {map, true}]), #winInfo{type=function, win=Win, packer=Frm, entries=Entries, trigger=enable, - ok=Ok, cancel=Cancel, listbox=Lb, funcs=[]}; + ok=OK, cancel=Cancel, listbox=Lb, funcs=[]}; create_win(GS, {X, Y}, Type, Mod, Line) -> Pad = 8, W = 230, @@ -161,12 +161,12 @@ create_win(GS, {X, Y}, Type, Mod, Line) -> {align, w}, {group, Grp}, {data, {trigger, delete}}]), - %% Add Ok and Cancel buttons - {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30), + %% Add OK and Cancel buttons + {Wbtn, Hbtn} = dbg_ui_win:min_size(["OK","Cancel"], 70, 30), Ybtn = Yacc + Pad + Hfrm + Pad, - Ok = gs:button(Win, [{x, Pad}, {y, Ybtn}, + OK = gs:button(Win, [{x, Pad}, {y, Ybtn}, {width, Wbtn}, {height, Hbtn}, - {label, {text,"Ok"}}, {font, Font}]), + {label, {text,"OK"}}, {font, Font}]), gs:button(Win, [{x, W-Pad-Wbtn}, {y, Ybtn}, {width, Wbtn}, {height, Hbtn}, {label, {text,"Cancel"}}, {font, Font}]), @@ -175,7 +175,7 @@ create_win(GS, {X, Y}, Type, Mod, Line) -> gs:config(Win, [{width, W}, {height, Hwin}, {map, true}]), #winInfo{type=Type, win=Win, - entries=Entries, trigger=enable, ok=Ok}. + entries=Entries, trigger=enable, ok=OK}. %%-------------------------------------------------------------------- %% update_functions(WinInfo, Funcs) -> WinInfo @@ -229,7 +229,7 @@ handle_event({gs, LB, keypress, window, [Key|_]}, WinInfo) -> Key/='Tab', Key/='Return' -> ignore; true -> - handle_event({gs, LB, click, listbox, ["Ok"]}, WinInfo) + handle_event({gs, LB, click, listbox, ["OK"]}, WinInfo) end; handle_event({gs, Ent, keypress, Data, [Key|_]}, WinInfo) -> case WinInfo#winInfo.type of @@ -249,14 +249,14 @@ handle_event({gs, Ent, keypress, Data, [Key|_]}, WinInfo) -> case next_entry(Ent, WinInfo#winInfo.entries) of last -> gs:config(WinInfo#winInfo.ok, flash), - handle_event({gs, Ent, click, Data, ["Ok"]}, WinInfo); + handle_event({gs, Ent, click, Data, ["OK"]}, WinInfo); Next -> gs:config(Next, {setfocus, true}), ignore end; _Type -> ignore end; -handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) -> +handle_event({gs, _Id, click, _Data, ["OK"|_]}, WinInfo) -> case check_input(WinInfo#winInfo.entries) of error -> ignore; Data when WinInfo#winInfo.type/=function -> diff --git a/lib/debugger/src/dbg_ui_edit_win.erl b/lib/debugger/src/dbg_ui_edit_win.erl index badaf4bef4..82f784aa83 100644 --- a/lib/debugger/src/dbg_ui_edit_win.erl +++ b/lib/debugger/src/dbg_ui_edit_win.erl @@ -64,13 +64,13 @@ create_win(GS, {X, Y}, Title, Prompt, {Type, Value}) -> {text, Value}, {keypress, true}]), - %% Ok and Cancel buttons + %% OK and Cancel buttons W = Pad + Wlbl + Went + Pad, {Wbtn, Hbtn} = dbg_ui_win:min_size(["Cancel"], 70, 30), Ybtn = Pad + Hlbl + Pad, Btn = gs:button(Win, [{x, Pad}, {y, Ybtn}, {width, Wbtn}, {height, Hbtn}, - {label, {text,"Ok"}}, {font, Font}]), + {label, {text,"OK"}}, {font, Font}]), gs:button(Win, [{x, W-Pad-Wbtn}, {y, Ybtn}, {width, Wbtn}, {height, Hbtn}, {label, {text,"Cancel"}}, {font, Font}]), @@ -100,8 +100,8 @@ handle_event({gs, _Id, destroy, _Data, _Arg}, _WinInfo) -> stopped; handle_event({gs, Id, keypress, Data, ['Return'|_]}, WinInfo) -> gs:config(WinInfo#winInfo.button, flash), - handle_event({gs, Id, click, Data, ["Ok"]}, WinInfo); -handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) -> + handle_event({gs, Id, click, Data, ["OK"]}, WinInfo); +handle_event({gs, _Id, click, _Data, ["OK"|_]}, WinInfo) -> Ent = WinInfo#winInfo.entry, Str = gs:read(Ent, text), Type = WinInfo#winInfo.type, diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl index 3203991c1f..1eced1104d 100644 --- a/lib/debugger/src/dbg_ui_filedialog_win.erl +++ b/lib/debugger/src/dbg_ui_filedialog_win.erl @@ -100,7 +100,7 @@ create_win(GS, Title, {X,Y}, Mode, Filter, Extra, FileName) -> Opts = [{y, Y4}, {width, Wbtn}, {height, Hbtn}, {font, Font}], case Mode of normal -> - gs:button(Win, [{label, {text,"Ok"}}, {x, Pad}, + gs:button(Win, [{label, {text,"OK"}}, {x, Pad}, {data, select} | Opts]), gs:button(Win, [{label, {text,"Filter"}}, {x, Wlb/2-Wbtn/2}, {data, filter} | Opts]), diff --git a/lib/debugger/src/dbg_ui_interpret.erl b/lib/debugger/src/dbg_ui_interpret.erl index 952e73b537..079eaeb634 100644 --- a/lib/debugger/src/dbg_ui_interpret.erl +++ b/lib/debugger/src/dbg_ui_interpret.erl @@ -145,7 +145,7 @@ interpret_all(State, Dir, [File0|Files]) -> Window = dbg_ui_filedialog_win:get_window(State#state.win), Error = format_error(int:interpretable(File)), Msg = ["Error when interpreting:", File, Error, - "Ok to continue?"], + "OK to continue?"], case tool_utils:confirm(Window, Msg) of ok -> interpret_all(State, Dir, Files); cancel -> true diff --git a/lib/debugger/src/dbg_ui_settings.erl b/lib/debugger/src/dbg_ui_settings.erl index 146aa7e239..38b2ec424f 100644 --- a/lib/debugger/src/dbg_ui_settings.erl +++ b/lib/debugger/src/dbg_ui_settings.erl @@ -136,8 +136,8 @@ default_settings_dir(GS) -> {ok, CWD} = file:get_cwd(), Msg = ["Default directory", DefDir, "does not exist.", - "Click Ok to create it or", - "Cancel to use other directory!"], + "Click OK to create it or", + "Cancel to use other directory."], case tool_utils:confirm(GS, Msg) of ok -> ToolsDir = filename:dirname(DefDir), diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl index 7ac82c8fb4..062da3937a 100644 --- a/lib/debugger/src/dbg_wx_break_win.erl +++ b/lib/debugger/src/dbg_wx_break_win.erl @@ -82,8 +82,8 @@ create_win(Parent, Pos, function, Mod, _Line) -> wxComboBox:connect(Text, command_text_updated), wxListBox:connect(LB, command_listbox_selected), wxListBox:connect(LB, command_listbox_doubleclicked), - OkId = wxDialog:getAffirmativeId(Win), - OKButt = wxWindow:findWindowById(OkId, [{parent, Win}]), + OKId = wxDialog:getAffirmativeId(Win), + OKButt = wxWindow:findWindowById(OKId, [{parent, Win}]), wxWindow:disable(OKButt), wxDialog:centreOnParent(Win), wxDialog:show(Win), @@ -141,8 +141,8 @@ create_win(Parent, Pos, Type, Mod, Line) -> wxComboBox:setFocus(ModT), wxDialog:connect(Win, command_button_clicked), wxDialog:connect(Win, command_text_updated), - OkId = wxDialog:getAffirmativeId(Win), - OKButt = wxWindow:findWindowById(OkId), + OKId = wxDialog:getAffirmativeId(Win), + OKButt = wxWindow:findWindowById(OKId), wxWindow:disable(OKButt), wxDialog:centreOnParent(Win), wxDialog:show(Win), @@ -180,30 +180,30 @@ handle_event(#wx{id=?wxID_CANCEL}, #winInfo{win=Win}) -> wxDialog:destroy(Win), stopped; handle_event(#wx{event=#wxCommand{type=command_text_updated}}, - #winInfo{type=function, text=Text, ok=Ok}) -> + #winInfo{type=function, text=Text, ok=OK}) -> Module = wxComboBox:getValue(Text), - wxWindow:disable(Ok), + wxWindow:disable(OK), {module, list_to_atom(Module)}; handle_event(#wx{event=#wxCommand{type=command_text_updated}}, - #winInfo{text=Text, ok=Ok, entries=Es}) -> + #winInfo{text=Text, ok=OK, entries=Es}) -> Module = wxComboBox:getValue(Text), case check_input(Es) of - error -> wxWindow:disable(Ok); - _Data when Module =/= "" -> wxWindow:enable(Ok); - _ -> wxWindow:disable(Ok) + error -> wxWindow:disable(OK); + _Data when Module =/= "" -> wxWindow:enable(OK); + _ -> wxWindow:disable(OK) end, ignore; handle_event(#wx{event=#wxCommand{type=command_listbox_selected}}, - #winInfo{type=function, listbox=LB, ok=Ok}) -> + #winInfo{type=function, listbox=LB, ok=OK}) -> case wxListBox:getSelections(LB) of - {N,_} when N > 0 -> wxWindow:enable(Ok); - _ -> wxWindow:disable(Ok) + {N,_} when N > 0 -> wxWindow:enable(OK); + _ -> wxWindow:disable(OK) end, ignore; -handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OkorDoubleClick}}, +handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OKorDoubleClick}}, #winInfo{type=function,win=Win,listbox=LB,funcs=Funcs,text=Text}) when OKorListBox =:= ?wxID_OK; - OkorDoubleClick =:= command_listbox_doubleclicked -> + OKorDoubleClick =:= command_listbox_doubleclicked -> Mod = wxComboBox:getValue(Text), {_, IndexL} = wxListBox:getSelections(LB), Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL], diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl index 9687efa981..9f45ad0c47 100644 --- a/lib/debugger/src/dbg_wx_filedialog_win.erl +++ b/lib/debugger/src/dbg_wx_filedialog_win.erl @@ -151,7 +151,7 @@ init([Parent, Id, Options0]) -> Bott = wxDialog:createButtonSizer(Dlg, ?wxCANCEL bor ?wxOK), wxDialog:connect(Dlg, command_button_clicked), - %% Ok done + %% OK done Box = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), diff --git a/lib/debugger/src/dbg_wx_settings.erl b/lib/debugger/src/dbg_wx_settings.erl index 8f87815949..bc88bdf7da 100644 --- a/lib/debugger/src/dbg_wx_settings.erl +++ b/lib/debugger/src/dbg_wx_settings.erl @@ -83,9 +83,9 @@ default_settings_dir(Win) -> false -> {ok, CWD} = file:get_cwd(), - Msg = ["Default directory", DefDir, "does not exist.", - "Click Ok to create it or", - "Cancel to use other directory!"], + Msg = ["Default directory ", DefDir, " does not exist. ", + "Click OK to create it or ", + "Cancel to use other directory."], case dbg_wx_win:confirm(Win, Msg) of ok -> ToolsDir = filename:dirname(DefDir), diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl index 720b913024..720b913024 100755..100644 --- a/lib/debugger/src/dbg_wx_trace_win.erl +++ b/lib/debugger/src/dbg_wx_trace_win.erl diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl index 79dcc47f6f..79dcc47f6f 100755..100644 --- a/lib/debugger/src/dbg_wx_winman.erl +++ b/lib/debugger/src/dbg_wx_winman.erl diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl index 8103d9c692..a06cdc7165 100644 --- a/lib/debugger/test/fun_SUITE.erl +++ b/lib/debugger/test/fun_SUITE.erl @@ -24,8 +24,10 @@ init_per_testcase/2,end_per_testcase/2, init_per_suite/1,end_per_suite/1, good_call/1,bad_apply/1,bad_fun_call/1,badarity/1, - ext_badarity/1,otp_6061/1]). --export([nothing/0]). + ext_badarity/1,otp_6061/1,external/1]). + +%% Internal exports. +-export([nothing/0,call_me/1]). -include_lib("test_server/include/test_server.hrl"). @@ -46,7 +48,7 @@ end_per_group(_GroupName, Config) -> cases() -> [good_call, bad_apply, bad_fun_call, badarity, - ext_badarity, otp_6061]. + ext_badarity, otp_6061, external]. init_per_testcase(_Case, Config) -> test_lib:interpret(?MODULE), @@ -244,3 +246,47 @@ test_otp_6061(Starter) -> fun() -> Starter ! working end, fun() -> Starter ! not_working end], lists:foreach(fun(P)->(lists:nth(P,PassesF))() end,Passes). + +-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)). +-define(APPLY2(M, F, A), + (fun(Map) -> + Id = fun(I) -> I end, + List = [x,y], + List = Map(Id, List), + {type,external} = erlang:fun_info(Map, type) + end)(fun M:F/A)). + +external(Config) when is_list(Config) -> + Mod = id(?MODULE), + Func = id(call_me), + Arity = id(1), + + ?APPLY(?MODULE, call_me, 1), + ?APPLY(?MODULE, call_me, Arity), + ?APPLY(?MODULE, Func, 1), + ?APPLY(?MODULE, Func, Arity), + ?APPLY(Mod, call_me, 1), + ?APPLY(Mod, call_me, Arity), + ?APPLY(Mod, Func, 1), + ?APPLY(Mod, Func, Arity), + + ListsMod = id(lists), + ListsMap = id(map), + ListsArity = id(2), + + ?APPLY2(lists, map, 2), + ?APPLY2(lists, map, ListsArity), + ?APPLY2(lists, ListsMap, 2), + ?APPLY2(lists, ListsMap, ListsArity), + ?APPLY2(ListsMod, map, 2), + ?APPLY2(ListsMod, map, ListsArity), + ?APPLY2(ListsMod, ListsMap, 2), + ?APPLY2(ListsMod, ListsMap, ListsArity), + + ok. + +call_me(I) -> + {ok,I}. + +id(I) -> + I. diff --git a/lib/dialyzer/doc/src/Makefile b/lib/dialyzer/doc/src/Makefile index 45b0ffa5ff..45b0ffa5ff 100755..100644 --- a/lib/dialyzer/doc/src/Makefile +++ b/lib/dialyzer/doc/src/Makefile diff --git a/lib/dialyzer/doc/src/book.xml b/lib/dialyzer/doc/src/book.xml index 0b4e1cb617..0b4e1cb617 100755..100644 --- a/lib/dialyzer/doc/src/book.xml +++ b/lib/dialyzer/doc/src/book.xml diff --git a/lib/dialyzer/doc/src/fascicules.xml b/lib/dialyzer/doc/src/fascicules.xml index 0678195e07..0678195e07 100755..100644 --- a/lib/dialyzer/doc/src/fascicules.xml +++ b/lib/dialyzer/doc/src/fascicules.xml diff --git a/lib/dialyzer/doc/src/make.dep b/lib/dialyzer/doc/src/make.dep deleted file mode 100755 index f8177cd419..0000000000 --- a/lib/dialyzer/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex dialyzer.tex dialyzer_chapter.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml index 17291b24f7..17291b24f7 100755..100644 --- a/lib/dialyzer/doc/src/notes.xml +++ b/lib/dialyzer/doc/src/notes.xml diff --git a/lib/dialyzer/doc/src/part.xml b/lib/dialyzer/doc/src/part.xml index 4410840660..4410840660 100755..100644 --- a/lib/dialyzer/doc/src/part.xml +++ b/lib/dialyzer/doc/src/part.xml diff --git a/lib/dialyzer/doc/src/part_notes.xml b/lib/dialyzer/doc/src/part_notes.xml index cb048d55dd..cb048d55dd 100755..100644 --- a/lib/dialyzer/doc/src/part_notes.xml +++ b/lib/dialyzer/doc/src/part_notes.xml diff --git a/lib/dialyzer/doc/src/ref_man.xml b/lib/dialyzer/doc/src/ref_man.xml index ca5410f6b8..ca5410f6b8 100755..100644 --- a/lib/dialyzer/doc/src/ref_man.xml +++ b/lib/dialyzer/doc/src/ref_man.xml diff --git a/lib/dialyzer/info b/lib/dialyzer/info index 9fba4b54ad..9fba4b54ad 100755..100644 --- a/lib/dialyzer/info +++ b/lib/dialyzer/info diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 5014a4244c..3e3c12405f 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -442,23 +442,29 @@ message_to_string({opaque_type_test, [Fun, Opaque]}) -> message_to_string({race_condition, [M, F, Args, Reason]}) -> io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]); %%----- Warnings for behaviour errors -------------------- -message_to_string({callback_type_mismatch, [B, F, A, O]}) -> - io_lib:format("The inferred return type of the ~w/~w callback includes the" - " type ~s which is not a valid return for the ~w behaviour\n", - [F, A, erl_types:t_to_string(O), B]); -message_to_string({callback_arg_type_mismatch, [B, F, A, N, O]}) -> - io_lib:format("The inferred type of the ~s argument of ~w/~w callback" - " includes the type ~s which is not valid for the ~w behaviour" - "\n", [ordinal(N), F, A, erl_types:t_to_string(O), B]); +message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) -> + io_lib:format("The inferred return type of ~w/~w (~s) has nothing in common" + " with ~s, which is the expected return type for the callback of" + " ~w behaviour\n", [F, A, ST, CT, B]); +message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) -> + io_lib:format("The inferred type for the ~s argument of ~w/~w (~s) is" + " not a supertype of ~s, which is expected type for this" + " argument in the callback of the ~w behaviour\n", + [ordinal(N), F, A, ST, CT, B]); +message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) -> + io_lib:format("The return type ~s in the specification of ~w/~w is not a" + " subtype of ~s, which is the expected return type for the" + " callback of ~w behaviour\n", [ST, F, A, CT, B]); +message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) -> + io_lib:format("The specified type for the ~s argument of ~w/~w (~s) is" + " not a supertype of ~s, which is expected type for this" + " argument in the callback of the ~w behaviour\n", + [ordinal(N), F, A, ST, CT, B]); message_to_string({callback_missing, [B, F, A]}) -> io_lib:format("Undefined callback function ~w/~w (behaviour '~w')\n", [F, A, B]); -message_to_string({invalid_spec, [B, F, A, R]}) -> - io_lib:format("The spec for the ~w:~w/~w callback is not correct: ~s\n", - [B, F, A, R]); -message_to_string({spec_missing, [B, F, A]}) -> - io_lib:format("Type info about ~w:~w/~w callback is not available\n", - [B, F, A]). +message_to_string({callback_info_missing, [B]}) -> + io_lib:format("Callback info about the ~w behaviour is not available\n", [B]). %%----------------------------------------------------------------------------- %% Auxiliary functions below diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl index 9d2e554981..5e089d1773 100644 --- a/lib/dialyzer/src/dialyzer.hrl +++ b/lib/dialyzer/src/dialyzer.hrl @@ -57,6 +57,7 @@ -define(WARN_UNMATCHED_RETURN, warn_umatched_return). -define(WARN_RACE_CONDITION, warn_race_condition). -define(WARN_BEHAVIOUR, warn_behaviour). +-define(WARN_UNDEFINED_CALLBACK, warn_undefined_callbacks). %% %% The following type has double role: @@ -71,7 +72,8 @@ | ?WARN_CONTRACT_NOT_EQUAL | ?WARN_CONTRACT_SUBTYPE | ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH | ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION - | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE. + | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE + | ?WARN_UNDEFINED_CALLBACK. %% %% This is the representation of each warning as they will be returned diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index abad1f3a75..62153fa176 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -43,8 +43,7 @@ parent :: pid(), plt :: dialyzer_plt:plt(), start_from = byte_code :: start_from(), - use_contracts = true :: boolean(), - behaviours = {false,[]} :: {boolean(),[atom()]} + use_contracts = true :: boolean() }). -record(server_state, {parent :: pid(), legal_warnings :: [dial_warn_tag()]}). @@ -57,9 +56,7 @@ start(Parent, LegalWarnings, Analysis) -> RacesOn = ordsets:is_element(?WARN_RACE_CONDITION, LegalWarnings), - BehavOn = ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings), - Analysis0 = Analysis#analysis{race_detection = RacesOn, - behaviours_chk = BehavOn}, + Analysis0 = Analysis#analysis{race_detection = RacesOn}, Analysis1 = expand_files(Analysis0), Analysis2 = run_analysis(Analysis1), State = #server_state{parent = Parent, legal_warnings = LegalWarnings}, @@ -125,8 +122,7 @@ analysis_start(Parent, Analysis) -> plt = Plt, parent = Parent, start_from = Analysis#analysis.start_from, - use_contracts = Analysis#analysis.use_contracts, - behaviours = {Analysis#analysis.behaviours_chk, []} + use_contracts = Analysis#analysis.use_contracts }, Files = ordsets:from_list(Analysis#analysis.files), {Callgraph, NoWarn, TmpCServer0} = compile_and_store(Files, State), @@ -180,8 +176,8 @@ analysis_start(Parent, Analysis) -> send_analysis_done(Parent, Plt4, State3#analysis_state.doc_plt). analyze_callgraph(Callgraph, State) -> - Plt = State#analysis_state.plt, Codeserver = State#analysis_state.codeserver, + Plt = dialyzer_plt:insert_callbacks(State#analysis_state.plt, Codeserver), Parent = State#analysis_state.parent, case State#analysis_state.analysis_type of plt_build -> @@ -192,13 +188,11 @@ analyze_callgraph(Callgraph, State) -> State#analysis_state{plt = NewPlt}; succ_typings -> NoWarn = State#analysis_state.no_warn_unused, - {BehavioursChk, _Known} = State#analysis_state.behaviours, DocPlt = State#analysis_state.doc_plt, Callgraph1 = dialyzer_callgraph:finalize(Callgraph), {Warnings, NewPlt, NewDocPlt} = dialyzer_succ_typings:get_warnings(Callgraph1, Plt, DocPlt, - Codeserver, NoWarn, Parent, - BehavioursChk), + Codeserver, NoWarn, Parent), dialyzer_callgraph:delete(Callgraph1), send_warnings(State#analysis_state.parent, Warnings), State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt} @@ -213,8 +207,7 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, include_dirs = Dirs, parent = Parent, use_contracts = UseContracts, - start_from = StartFrom, - behaviours = {BehChk, _} + start_from = StartFrom } = State) -> send_log(Parent, "Reading files and computing callgraph... "), {T1, _} = statistics(runtime), @@ -263,37 +256,26 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, {T2, _} = statistics(runtime), Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]), send_log(Parent, Msg1), - {KnownBehaviours, UnknownBehaviours} = - dialyzer_behaviours:get_behaviours(Modules, NewCServer), - if UnknownBehaviours =:= [] -> ok; - true -> send_unknown_behaviours(Parent, UnknownBehaviours) - end, - State1 = State#analysis_state{behaviours = {BehChk, KnownBehaviours}}, - NewCallgraph2 = cleanup_callgraph(State1, NewCServer, NewCallgraph1, Modules), + NewCallgraph2 = cleanup_callgraph(State, NewCServer, NewCallgraph1, Modules), {T3, _} = statistics(runtime), Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]), send_log(Parent, Msg2), {NewCallgraph2, sets:from_list(NoWarn), NewCServer}. cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent, - codeserver = CodeServer, - behaviours = {BehChk, KnownBehaviours} + codeserver = CodeServer }, CServer, Callgraph, Modules) -> ModuleDeps = dialyzer_callgraph:module_deps(Callgraph), send_mod_deps(Parent, ModuleDeps), {Callgraph1, ExtCalls} = dialyzer_callgraph:remove_external(Callgraph), - if BehChk -> - RelevantAPICalls = - dialyzer_behaviours:get_behaviour_apis(KnownBehaviours), - BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls, - lists:member(To, RelevantAPICalls)], - Callgraph2 = - dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls, - Callgraph1); - true -> - Callgraph2 = Callgraph1 - end, + RelevantAPICalls = + dialyzer_behaviours:get_behaviour_apis([gen_server]), + BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls, + lists:member(To, RelevantAPICalls)], + Callgraph2 = + dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls, + Callgraph1), ExtCalls1 = [Call || Call = {_From, To} <- ExtCalls, not dialyzer_plt:contains_mfa(InitPlt, To)], {BadCalls1, RealExtCalls} = @@ -325,63 +307,42 @@ compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) -> case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of {error, _Msg} = Error -> Error; {ok, AbstrCode} -> - case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of - error -> {error, " Could not find abstract code for: " ++ File}; - {ok, Core} -> - Mod = cerl:concrete(cerl:module_name(Core)), - NoWarn = abs_get_nowarn(AbstrCode, Mod), - case dialyzer_utils:get_record_and_type_info(AbstrCode) of - {error, _} = Error -> Error; - {ok, RecInfo} -> - CServer2 = - dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer), - case UseContracts of - true -> - case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of - {error, _} = Error -> Error; - {ok, SpecInfo} -> - CServer3 = - dialyzer_codeserver:store_temp_contracts(Mod, - SpecInfo, - CServer2), - store_core(Mod, Core, NoWarn, Callgraph, CServer3) - end; - false -> - store_core(Mod, Core, NoWarn, Callgraph, CServer2) - end - end - end + compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) end. compile_byte(File, Callgraph, CServer, UseContracts) -> case dialyzer_utils:get_abstract_code_from_beam(File) of error -> {error, " Could not get abstract code for: " ++ File ++ "\n" ++ - " Recompile with +debug_info or analyze starting from source code"}; + " Recompile with +debug_info or analyze starting from source code"}; {ok, AbstrCode} -> - case dialyzer_utils:get_core_from_abstract_code(AbstrCode) of - error -> {error, " Could not get core for: "++File}; - {ok, Core} -> - Mod = cerl:concrete(cerl:module_name(Core)), - NoWarn = abs_get_nowarn(AbstrCode, Mod), - case dialyzer_utils:get_record_and_type_info(AbstrCode) of - {error, _} = Error -> Error; - {ok, RecInfo} -> - CServer1 = - dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer), - case UseContracts of - true -> - case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of - {error, _} = Error -> Error; - {ok, SpecInfo} -> - CServer2 = - dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo, - CServer1), - store_core(Mod, Core, NoWarn, Callgraph, CServer2) - end; - false -> - store_core(Mod, Core, NoWarn, Callgraph, CServer1) - end + compile_common(File, AbstrCode, [], Callgraph, CServer, UseContracts) + end. + +compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) -> + case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of + error -> {error, " Could not get core Erlang code for: " ++ File}; + {ok, Core} -> + Mod = cerl:concrete(cerl:module_name(Core)), + NoWarn = abs_get_nowarn(AbstrCode, Mod), + case dialyzer_utils:get_record_and_type_info(AbstrCode) of + {error, _} = Error -> Error; + {ok, RecInfo} -> + CServer1 = + dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer), + case UseContracts of + true -> + case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of + {error, _} = Error -> Error; + {ok, SpecInfo, CallbackInfo} -> + CServer2 = + dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo, + CallbackInfo, + CServer1), + store_core(Mod, Core, NoWarn, Callgraph, CServer2) + end; + false -> + store_core(Mod, Core, NoWarn, Callgraph, CServer1) end end end. diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl index 47ce9ba6eb..56eb46d78a 100644 --- a/lib/dialyzer/src/dialyzer_behaviours.erl +++ b/lib/dialyzer/src/dialyzer_behaviours.erl @@ -30,7 +30,7 @@ -module(dialyzer_behaviours). --export([check_callbacks/4, get_behaviours/2, get_behaviour_apis/1, +-export([check_callbacks/4, get_behaviour_apis/1, translate_behaviour_api_call/5, translatable_behaviours/1, translate_callgraph/3]). @@ -51,12 +51,6 @@ %%-------------------------------------------------------------------- --spec get_behaviours([module()], dialyzer_codeserver:codeserver()) -> - {[behaviour()], [behaviour()]}. - -get_behaviours(Modules, Codeserver) -> - get_behaviours(Modules, Codeserver, [], []). - -spec check_callbacks(module(), [{cerl:cerl(), cerl:cerl()}], dialyzer_plt:plt(), dialyzer_codeserver:codeserver()) -> [dial_warning()]. @@ -69,12 +63,165 @@ check_callbacks(Module, Attrs, Plt, Codeserver) -> MFA = {Module,module_info,0}, {_Var,Code} = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver), File = get_file(cerl:get_ann(Code)), - State = #state{plt = Plt, codeserver = Codeserver, filename = File, - behlines = BehLines}, + State = #state{plt = Plt, filename = File, behlines = BehLines, + codeserver = Codeserver}, Warnings = get_warnings(Module, Behaviours, State), [add_tag_file_line(Module, W, State) || W <- Warnings] end. +%%-------------------------------------------------------------------- + +get_behaviours(Attrs) -> + BehaviourListsAndLine = [{cerl:concrete(L2), hd(cerl:get_ann(L2))} || + {L1, L2} <- Attrs, cerl:is_literal(L1), + cerl:is_literal(L2), cerl:concrete(L1) =:= 'behaviour'], + Behaviours = lists:append([Behs || {Behs,_} <- BehaviourListsAndLine]), + BehLines = [{B,L} || {L1,L} <- BehaviourListsAndLine, B <- L1], + {Behaviours, BehLines}. + +get_warnings(Module, Behaviours, State) -> + get_warnings(Module, Behaviours, State, []). + +get_warnings(_, [], _, Acc) -> + Acc; +get_warnings(Module, [Behaviour|Rest], State, Acc) -> + NewAcc = check_behaviour(Module, Behaviour, State, Acc), + get_warnings(Module, Rest, State, NewAcc). + +check_behaviour(Module, Behaviour, #state{plt = Plt} = State, Acc) -> + case dialyzer_plt:lookup_callbacks(Plt, Behaviour) of + [] -> [{callback_info_missing, [Behaviour]}|Acc]; + Callbacks -> check_all_callbacks(Module, Behaviour, Callbacks, State, Acc) + end. + +check_all_callbacks(_Module, _Behaviour, [], _State, Acc) -> + Acc; +check_all_callbacks(Module, Behaviour, [Cb|Rest], + #state{plt = Plt, codeserver = Codeserver} = State, Acc) -> + {{Behaviour, Function, Arity}, + {{_BehFile, _BehLine}, Callback}} = Cb, + CbMFA = {Module, Function, Arity}, + CbReturnType = dialyzer_contracts:get_contract_return(Callback), + CbArgTypes = dialyzer_contracts:get_contract_args(Callback), + Records = + case dict:find(Module, dialyzer_codeserver:get_records(Codeserver)) of + {ok, V} -> V; + error -> dict:new() + end, + Acc0 = Acc, + Acc1 = + case dialyzer_plt:lookup(Plt, CbMFA) of + 'none' -> [{callback_missing, [Behaviour, Function, Arity]}|Acc0]; + {'value', RetArgTypes} -> + Acc00 = Acc0, + {ReturnType, ArgTypes} = RetArgTypes, + Acc01 = + case erl_types:t_is_subtype(ReturnType, CbReturnType) of + true -> Acc00; + false -> + case erl_types:t_is_none( + erl_types:t_inf(ReturnType, CbReturnType)) of + false -> Acc00; + true -> + [{callback_type_mismatch, + [Behaviour, Function, Arity, + erl_types:t_to_string(ReturnType, Records), + erl_types:t_to_string(CbReturnType, Records)]}|Acc00] + end + end, + Acc02 = + case erl_types:any_none( + erl_types:t_inf_lists(ArgTypes, CbArgTypes)) of + false -> Acc01; + true -> + find_mismatching_args(type, ArgTypes, CbArgTypes, Behaviour, + Function, Arity, Records, 1, Acc01) + end, + Acc02 + end, + Acc2 = + case dialyzer_codeserver:lookup_mfa_contract(CbMFA, Codeserver) of + 'error' -> Acc1; + {ok, {{File, Line}, Contract}} -> + Acc10 = Acc1, + SpecReturnType = dialyzer_contracts:get_contract_return(Contract), + SpecArgTypes = dialyzer_contracts:get_contract_args(Contract), + Acc11 = + case erl_types:t_is_subtype(SpecReturnType, CbReturnType) of + true -> Acc10; + false -> [{callback_spec_type_mismatch, + [File, Line, Behaviour, Function, Arity, + erl_types:t_to_string(SpecReturnType, Records), + erl_types:t_to_string(CbReturnType, Records)]}|Acc10] + end, + Acc12 = + case erl_types:any_none( + erl_types:t_inf_lists(SpecArgTypes, CbArgTypes)) of + false -> Acc11; + true -> + find_mismatching_args({spec, File, Line}, SpecArgTypes, + CbArgTypes, Behaviour, Function, + Arity, Records, 1, Acc11) + end, + Acc12 + end, + NewAcc = Acc2, + check_all_callbacks(Module, Behaviour, Rest, State, NewAcc). + +find_mismatching_args(_, [], [], _Beh, _Function, _Arity, _Records, _N, Acc) -> + Acc; +find_mismatching_args(Kind, [Type|Rest], [CbType|CbRest], Behaviour, + Function, Arity, Records, N, Acc) -> + case erl_types:t_is_none(erl_types:t_inf(Type, CbType)) of + false -> + find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function, + Arity, Records, N+1, Acc); + true -> + Info = + [Behaviour, Function, Arity, N, + erl_types:t_to_string(Type, Records), + erl_types:t_to_string(CbType, Records)], + NewAcc = + [case Kind of + type -> {callback_arg_type_mismatch, Info}; + {spec, File, Line} -> + {callback_spec_arg_type_mismatch, [File, Line | Info]} + end | Acc], + find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function, + Arity, Records, N+1, NewAcc) + end. + +add_tag_file_line(_Module, {Tag, [B|_R]} = Warn, State) + when Tag =:= callback_missing; + Tag =:= callback_info_missing -> + {B, Line} = lists:keyfind(B, 1, State#state.behlines), + Category = + case Tag of + callback_missing -> ?WARN_BEHAVIOUR; + callback_info_missing -> ?WARN_UNDEFINED_CALLBACK + end, + {Category, {State#state.filename, Line}, Warn}; +add_tag_file_line(_Module, {Tag, [File, Line|R]}, _State) + when Tag =:= callback_spec_type_mismatch; + Tag =:= callback_spec_arg_type_mismatch -> + {?WARN_BEHAVIOUR, {File, Line}, {Tag, R}}; +add_tag_file_line(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) -> + {_A, FunCode} = + dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity}, + State#state.codeserver), + Anns = cerl:get_ann(FunCode), + FileLine = {get_file(Anns), get_line(Anns)}, + {?WARN_BEHAVIOUR, FileLine, Warn}. + +get_line([Line|_]) when is_integer(Line) -> Line; +get_line([_|Tail]) -> get_line(Tail); +get_line([]) -> -1. + +get_file([{file, File}|_]) -> File; +get_file([_|Tail]) -> get_file(Tail). + +%%----------------------------------------------------------------------------- + -spec translatable_behaviours(cerl:c_module()) -> behaviour_api_dict(). translatable_behaviours(Tree) -> @@ -133,182 +280,6 @@ translate_callgraph([{Behaviour,_}|Behaviours], Module, Callgraph) -> translate_callgraph([], _Module, Callgraph) -> Callgraph. -%%-------------------------------------------------------------------- - -get_behaviours(Attrs) -> - BehaviourListsAndLine = [{cerl:concrete(L2), hd(cerl:get_ann(L2))} || - {L1, L2} <- Attrs, cerl:is_literal(L1), - cerl:is_literal(L2), cerl:concrete(L1) =:= 'behaviour'], - Behaviours = lists:append([Behs || {Behs,_} <- BehaviourListsAndLine]), - BehLines = [{B,L} || {L1,L} <- BehaviourListsAndLine, B <- L1], - {Behaviours, BehLines}. - -get_warnings(Module, Behaviours, State) -> - get_warnings(Module, Behaviours, State, []). - -get_warnings(_, [], _, Acc) -> - Acc; -get_warnings(Module, [Behaviour|Rest], State, Acc) -> - Warnings = check_behaviour(Module, Behaviour, State), - get_warnings(Module, Rest, State, Warnings ++ Acc). - -check_behaviour(Module, Behaviour, State) -> - try - Callbacks = Behaviour:behaviour_info(callbacks), - Fun = fun({_,_,_}) -> true; - (_) -> false - end, - case lists:any(Fun, Callbacks) of - true -> check_all_callbacks(Module, Behaviour, Callbacks, State); - false -> [] - end - catch - _:_ -> [] - end. - -check_all_callbacks(Module, Behaviour, Callbacks, State) -> - check_all_callbacks(Module, Behaviour, Callbacks, State, []). - -check_all_callbacks(_Module, _Behaviour, [], _State, Acc) -> - Acc; -check_all_callbacks(Module, Behaviour, [{Fun, Arity, Spec}|Rest], - #state{codeserver = CServer} = State, Acc) -> - Records = dialyzer_codeserver:get_records(CServer), - ExpTypes = dialyzer_codeserver:get_exported_types(CServer), - case parse_spec(Spec, ExpTypes, Records) of - {ok, Fun, Type} -> - RetType = erl_types:t_fun_range(Type), - ArgTypes = erl_types:t_fun_args(Type), - Warns = check_callback(Module, Behaviour, Fun, Arity, RetType, - ArgTypes, State#state.plt); - Else -> - Warns = [{invalid_spec, [Behaviour, Fun, Arity, reason_spec_error(Else)]}] - end, - check_all_callbacks(Module, Behaviour, Rest, State, Warns ++ Acc); -check_all_callbacks(Module, Behaviour, [{Fun, Arity}|Rest], State, Acc) -> - Warns = {spec_missing, [Behaviour, Fun, Arity]}, - check_all_callbacks(Module, Behaviour, Rest, State, [Warns|Acc]). - -parse_spec(String, ExpTypes, Records) -> - case erl_scan:string(String) of - {ok, Tokens, _} -> - case erl_parse:parse(Tokens) of - {ok, Form} -> - case Form of - {attribute, _, 'spec', {{Fun, _}, [TypeForm|_Constraint]}} -> - MaybeRemoteType = erl_types:t_from_form(TypeForm), - try - Type = erl_types:t_solve_remote(MaybeRemoteType, ExpTypes, - Records), - {ok, Fun, Type} - catch - throw:{error,Msg} -> {spec_remote_error, Msg} - end; - _Other -> not_a_spec - end; - {error, {Line, _, Msg}} -> {spec_parser_error, Line, Msg} - end; - _Other -> - lexer_error - end. - -reason_spec_error({spec_remote_error, Msg}) -> - io_lib:format("Remote type solver error: ~s. Make sure the behaviour source is included in the analysis or the plt",[Msg]); -reason_spec_error(not_a_spec) -> - "This is not a spec"; -reason_spec_error({spec_parser_error, Line, Msg}) -> - io_lib:format("~s line of the spec: ~s", [ordinal(Line),Msg]); -reason_spec_error(lexer_error) -> - "Lexical error". - -ordinal(1) -> "1st"; -ordinal(2) -> "2nd"; -ordinal(3) -> "3rd"; -ordinal(N) when is_integer(N) -> io_lib:format("~wth",[N]). - -check_callback(Module, Behaviour, Fun, Arity, XRetType, XArgTypes, Plt) -> - LookupType = dialyzer_plt:lookup(Plt, {Module, Fun, Arity}), - case LookupType of - {value, {Type,Args}} -> - Warn1 = case unifiable(Type, XRetType) of - [] -> []; - Offenders -> - [{callback_type_mismatch, - [Behaviour, Fun, Arity, erl_types:t_sup(Offenders)]}] - end, - ZipArgs = lists:zip3(lists:seq(1, Arity), Args, XArgTypes), - Warn2 = [{callback_arg_type_mismatch, - [Behaviour, Fun, Arity, N, - erl_types:t_sup(Offenders)]} || - {Offenders, N} <- [check_callback_1(V) || V <- ZipArgs], - Offenders =/= []], - Warn1 ++ Warn2; - _ -> [{callback_missing, [Behaviour, Fun, Arity]}] - end. - -check_callback_1({N, T1, T2}) -> - {unifiable(T1, T2), N}. - -unifiable(Type1, Type2) -> - List1 = erl_types:t_elements(Type1), - List2 = erl_types:t_elements(Type2), - [T || T <- List1, - lists:all(fun(T1) -> - erl_types:t_is_none(erl_types:t_inf(T, T1, opaque)) - end, List2)]. - -add_tag_file_line(_Module, {Tag, [B|_R]} = Warn, State) - when Tag =:= spec_missing; - Tag =:= invalid_spec; - Tag =:= callback_missing -> - {B, Line} = lists:keyfind(B, 1, State#state.behlines), - {?WARN_BEHAVIOUR, {State#state.filename, Line}, Warn}; -add_tag_file_line(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) -> - {_A, FunCode} = - dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity}, - State#state.codeserver), - Anns = cerl:get_ann(FunCode), - FileLine = {get_file(Anns), get_line(Anns)}, - {?WARN_BEHAVIOUR, FileLine, Warn}. - -get_line([Line|_]) when is_integer(Line) -> Line; -get_line([_|Tail]) -> get_line(Tail); -get_line([]) -> -1. - -get_file([{file, File}|_]) -> File; -get_file([_|Tail]) -> get_file(Tail). - -%%----------------------------------------------------------------------------- - -get_behaviours([], _Codeserver, KnownAcc, UnknownAcc) -> - {KnownAcc, UnknownAcc}; -get_behaviours([M|Rest], Codeserver, KnownAcc, UnknownAcc) -> - Tree = dialyzer_codeserver:lookup_mod_code(M, Codeserver), - Attrs = cerl:module_attrs(Tree), - {Behaviours, _BehLines} = get_behaviours(Attrs), - {Known, Unknown} = call_behaviours(Behaviours), - get_behaviours(Rest, Codeserver, Known ++ KnownAcc, Unknown ++ UnknownAcc). - -call_behaviours(Behaviours) -> - call_behaviours(Behaviours, [], []). -call_behaviours([], KnownAcc, UnknownAcc) -> - {lists:reverse(KnownAcc), lists:reverse(UnknownAcc)}; -call_behaviours([Behaviour|Rest], KnownAcc, UnknownAcc) -> - try - Callbacks = Behaviour:behaviour_info(callbacks), - Fun = fun({_,_,_}) -> true; - (_) -> false - end, - case lists:any(Fun, Callbacks) of - false -> call_behaviours(Rest, KnownAcc, [Behaviour | UnknownAcc]); - true -> call_behaviours(Rest, [Behaviour | KnownAcc], UnknownAcc) - end - catch - _:_ -> call_behaviours(Rest, KnownAcc, [Behaviour | UnknownAcc]) - end. - -%------------------------------------------------------------------------------ - get_behaviour_apis([], Acc) -> Acc; get_behaviour_apis([Behaviour | Rest], Acc) -> diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 8d61216b7a..e638e2fff2 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -754,15 +754,13 @@ print_unknown_behaviours(#cl_state{output = Output, true -> io:nl(Output); %% Need to do a newline first false -> ok end, - case Format of - formatted -> - io:put_chars(Output, "Unknown behaviours (behaviour_info(callbacks)" - " does not return any specs):\n"), - do_print_unknown_behaviours(Output, Behaviours, " "); - raw -> - io:put_chars(Output, "%% Unknown behaviours:\n"), - do_print_unknown_behaviours(Output, Behaviours, "%% ") - end + {Prompt, Prefix} = + case Format of + formatted -> {"Unknown behaviours:\n"," "}; + raw -> {"%% Unknown behaviours:\n","%% "} + end, + io:put_chars(Output, Prompt), + do_print_unknown_behaviours(Output, Behaviours, Prefix) end. do_print_unknown_behaviours(Output, [B|T], Before) -> diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index f80eb81ac6..ff8fc39a5e 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -491,6 +491,12 @@ warning_options_msg() -> Suppress warnings for patterns that are unused or cannot match. -Wno_opaque Suppress warnings for violations of opaqueness of data types. + -Wno_behaviours + Suppress warnings about behaviour callbacks which drift from the published + recommended interfaces. + -Wno_undefined_callbacks + Suppress warnings about behaviours that have no -callback attributes for + their callbacks. -Wunmatched_returns *** Include warnings for function calls which ignore a structured return value or do not match against one of many possible return value(s). @@ -498,9 +504,6 @@ warning_options_msg() -> Include warnings for functions that only return by means of an exception. -Wrace_conditions *** Include warnings for possible race conditions. - -Wbehaviours *** - Include warnings about behaviour callbacks which drift from the published - recommended interfaces. -Wunderspecs *** Warn about underspecified functions (those whose -spec is strictly more allowing than the success typing). diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl index b2097f7e53..c34a9f0b7d 100644 --- a/lib/dialyzer/src/dialyzer_codeserver.erl +++ b/lib/dialyzer/src/dialyzer_codeserver.erl @@ -28,10 +28,11 @@ -module(dialyzer_codeserver). -export([delete/1, - finalize_contracts/2, + finalize_contracts/3, finalize_exported_types/2, finalize_records/2, get_contracts/1, + get_callbacks/1, get_exported_types/1, get_exports/1, get_records/1, @@ -54,7 +55,7 @@ store_records/3, store_temp_records/3, store_contracts/3, - store_temp_contracts/3]). + store_temp_contracts/4]). -export_type([codeserver/0]). @@ -70,7 +71,10 @@ records = dict:new() :: dict(), temp_records = dict:new() :: dict(), contracts = dict:new() :: dict(), - temp_contracts = dict:new() :: dict()}). + callbacks = dict:new() :: dict(), + temp_contracts = dict:new() :: dict(), + temp_callbacks = dict:new() :: dict() + }). -opaque codeserver() :: #codeserver{}. @@ -227,24 +231,42 @@ lookup_mfa_contract({M,_F,_A} = MFA, #codeserver{contracts = ContDict}) -> get_contracts(#codeserver{contracts = ContDict}) -> ContDict. --spec store_temp_contracts(atom(), dict(), codeserver()) -> codeserver(). +-spec get_callbacks(codeserver()) -> dict(). -store_temp_contracts(Mod, Dict, #codeserver{temp_contracts = C} = CS) +get_callbacks(#codeserver{callbacks = CallbDict}) -> + CallbDict. + +-spec store_temp_contracts(atom(), dict(), dict(), codeserver()) -> + codeserver(). + +store_temp_contracts(Mod, SpecDict, CallbackDict, + #codeserver{temp_contracts = Cn, + temp_callbacks = Cb} = CS) when is_atom(Mod) -> - case dict:size(Dict) =:= 0 of - true -> CS; - false -> CS#codeserver{temp_contracts = dict:store(Mod, Dict, C)} + CS1 = + case dict:size(SpecDict) =:= 0 of + true -> CS; + false -> CS#codeserver{temp_contracts = dict:store(Mod, SpecDict, Cn)} + end, + case dict:size(CallbackDict) =:= 0 of + true -> CS1; + false -> CS1#codeserver{temp_callbacks = dict:store(Mod, CallbackDict, Cb)} end. --spec get_temp_contracts(codeserver()) -> dict(). +-spec get_temp_contracts(codeserver()) -> {dict(), dict()}. -get_temp_contracts(#codeserver{temp_contracts = TempContDict}) -> - TempContDict. +get_temp_contracts(#codeserver{temp_contracts = TempContDict, + temp_callbacks = TempCallDict}) -> + {TempContDict, TempCallDict}. --spec finalize_contracts(dict(), codeserver()) -> codeserver(). +-spec finalize_contracts(dict(), dict(), codeserver()) -> codeserver(). -finalize_contracts(Dict, CS) -> - CS#codeserver{contracts = Dict, temp_contracts = dict:new()}. +finalize_contracts(CnDict, CbDict, CS) -> + CS#codeserver{contracts = CnDict, + callbacks = CbDict, + temp_contracts = dict:new(), + temp_callbacks = dict:new() + }. table__new() -> spawn_link(fun() -> table__loop(none, dict:new()) end). diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index bcdcf2685d..3469d70a4d 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -141,7 +141,8 @@ sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter). dialyzer_codeserver:codeserver(). process_contract_remote_types(CodeServer) -> - TmpContractDict = dialyzer_codeserver:get_temp_contracts(CodeServer), + {TmpContractDict, TmpCallbackDict} = + dialyzer_codeserver:get_temp_contracts(CodeServer), ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer), RecordDict = dialyzer_codeserver:get_records(CodeServer), ContractFun = @@ -155,7 +156,9 @@ process_contract_remote_types(CodeServer) -> dict:map(ContractFun, ContractDict) end, NewContractDict = dict:map(ModuleFun, TmpContractDict), - dialyzer_codeserver:finalize_contracts(NewContractDict, CodeServer). + NewCallbackDict = dict:map(ModuleFun, TmpCallbackDict), + dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict, + CodeServer). -spec check_contracts([{mfa(), file_contract()}], dialyzer_callgraph:callgraph(), dict()) -> plt_contracts(). @@ -480,7 +483,7 @@ invalid_contract_warning({M, F, A}, FileLine, SuccType, RecDict) -> extra_range_warning({M, F, A}, FileLine, ExtraRanges, STRange) -> ERangesStr = erl_types:t_to_string(ExtraRanges), STRangeStr = erl_types:t_to_string(STRange), - {?WARN_CONTRACT_TYPES, FileLine, + {?WARN_CONTRACT_SUPERTYPE, FileLine, {extra_range, [M, F, A, ERangesStr, STRangeStr]}}. picky_contract_check(CSig0, Sig0, MFA, FileLine, Contract, RecDict, Acc) -> diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index b2a67de8bd..866650a0b2 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -49,7 +49,9 @@ build(Opts) -> ?WARN_CALLGRAPH, ?WARN_CONTRACT_RANGE, ?WARN_CONTRACT_TYPES, - ?WARN_CONTRACT_SYNTAX], + ?WARN_CONTRACT_SYNTAX, + ?WARN_BEHAVIOUR, + ?WARN_UNDEFINED_CALLBACK], DefaultWarns1 = ordsets:from_list(DefaultWarns), InitPlt = dialyzer_plt:get_default_plt(), DefaultOpts = #options{}, @@ -275,14 +277,16 @@ build_warnings([Opt|Opts], Warnings) -> no_contracts -> Warnings1 = ordsets:del_element(?WARN_CONTRACT_SYNTAX, Warnings), ordsets:del_element(?WARN_CONTRACT_TYPES, Warnings1); + no_behaviours -> + ordsets:del_element(?WARN_BEHAVIOUR, Warnings); + no_undefined_callbacks -> + ordsets:del_element(?WARN_UNDEFINED_CALLBACK, Warnings); unmatched_returns -> ordsets:add_element(?WARN_UNMATCHED_RETURN, Warnings); error_handling -> ordsets:add_element(?WARN_RETURN_ONLY_EXIT, Warnings); race_conditions -> ordsets:add_element(?WARN_RACE_CONDITION, Warnings); - behaviours -> - ordsets:add_element(?WARN_BEHAVIOUR, Warnings); specdiffs -> S = ordsets:from_list([?WARN_CONTRACT_SUBTYPE, ?WARN_CONTRACT_SUPERTYPE, diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 6033d7f17c..206c43e4e2 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -43,10 +43,12 @@ %% insert/3, insert_list/2, insert_contract_list/2, + insert_callbacks/2, insert_types/2, insert_exported_types/2, lookup/2, lookup_contract/2, + lookup_callbacks/2, lookup_module/2, merge_plts/1, merge_plts_or_report_conflicts/2, @@ -79,6 +81,7 @@ -record(plt, {info = table_new() :: dict(), types = table_new() :: dict(), contracts = table_new() :: dict(), + callbacks = table_new() :: dict(), exported_types = sets:new() :: set()}). -opaque plt() :: #plt{}. @@ -91,6 +94,7 @@ file_md5_list = [] :: [file_md5()], info = dict:new() :: dict(), contracts = dict:new() :: dict(), + callbacks = dict:new() :: dict(), types = dict:new() :: dict(), exported_types = sets:new() :: set(), mod_deps :: mod_deps(), @@ -105,20 +109,26 @@ new() -> -spec delete_module(plt(), atom()) -> plt(). -delete_module(#plt{info = Info, types = Types, contracts = Contracts, +delete_module(#plt{info = Info, types = Types, + contracts = Contracts, + callbacks = Callbacks, exported_types = ExpTypes}, Mod) -> #plt{info = table_delete_module(Info, Mod), types = table_delete_module2(Types, Mod), contracts = table_delete_module(Contracts, Mod), + callbacks = table_delete_module(Callbacks, Mod), exported_types = table_delete_module1(ExpTypes, Mod)}. -spec delete_list(plt(), [mfa() | integer()]) -> plt(). -delete_list(#plt{info = Info, types = Types, contracts = Contracts, +delete_list(#plt{info = Info, types = Types, + contracts = Contracts, + callbacks = Callbacks, exported_types = ExpTypes}, List) -> #plt{info = table_delete_list(Info, List), types = Types, contracts = table_delete_list(Contracts, List), + callbacks = table_delete_list(Callbacks, List), exported_types = ExpTypes}. -spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt(). @@ -126,16 +136,42 @@ delete_list(#plt{info = Info, types = Types, contracts = Contracts, insert_contract_list(#plt{contracts = Contracts} = PLT, List) -> PLT#plt{contracts = table_insert_list(Contracts, List)}. +-spec insert_callbacks(plt(), dialyzer_codeserver:codeserver()) -> plt(). + +insert_callbacks(#plt{callbacks = Callbacks} = Plt, Codeserver) -> + FunPreferNew = fun(_Key, _Val1, Val2) -> Val2 end, + FunDictMerger = + fun(_Key, Value, AccIn) -> dict:merge(FunPreferNew, Value, AccIn) end, + MergedCallbacks = dict:fold(FunDictMerger, dict:new(), + dialyzer_codeserver:get_callbacks(Codeserver)), + List = dict:to_list(MergedCallbacks), + Plt#plt{callbacks = table_insert_list(Callbacks, List)}. + -spec lookup_contract(plt(), mfa_patt()) -> 'none' | {'value', #contract{}}. lookup_contract(#plt{contracts = Contracts}, {M, F, _} = MFA) when is_atom(M), is_atom(F) -> table_lookup(Contracts, MFA). +-spec lookup_callbacks(plt(), module()) -> [{mfa(), + {{Filename::string(), + Line::pos_integer()}, + #contract{}}}]. + +lookup_callbacks(#plt{callbacks = Callbacks}, Mod) when is_atom(Mod) -> + FunModFilter = + fun({M, _F, _A}, _Val) -> M =:= Mod; + ( _Key, _Val) -> false + end, + ModCallbacks = dict:filter(FunModFilter, Callbacks), + dict:to_list(ModCallbacks). + -spec delete_contract_list(plt(), [mfa()]) -> plt(). -delete_contract_list(#plt{contracts = Contracts} = PLT, List) -> - PLT#plt{contracts = table_delete_list(Contracts, List)}. +delete_contract_list(#plt{contracts = Contracts, + callbacks = Callbacks} = PLT, List) -> + PLT#plt{contracts = table_delete_list(Contracts, List), + callbacks = table_delete_list(Callbacks, List)}. %% -spec insert(plt(), mfa() | integer(), {_, _}) -> plt(). %% @@ -230,6 +266,7 @@ from_file(FileName, ReturnInfo) -> Plt = #plt{info = Rec#file_plt.info, types = Rec#file_plt.types, contracts = Rec#file_plt.contracts, + callbacks = Rec#file_plt.callbacks, exported_types = Rec#file_plt.exported_types}, case ReturnInfo of false -> Plt; @@ -284,26 +321,34 @@ get_record_from_file(FileName) -> -spec merge_plts([plt()]) -> plt(). merge_plts(List) -> - InfoList = [Info || #plt{info = Info} <- List], - TypesList = [Types || #plt{types = Types} <- List], - ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List], - ContractsList = [Contracts || #plt{contracts = Contracts} <- List], + {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} = + group_fields(List), #plt{info = table_merge(InfoList), types = table_merge(TypesList), exported_types = sets_merge(ExpTypesList), - contracts = table_merge(ContractsList)}. + contracts = table_merge(ContractsList), + callbacks = table_merge(CallbacksList) + }. -spec merge_disj_plts([plt()]) -> plt(). merge_disj_plts(List) -> + {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} = + group_fields(List), + #plt{info = table_disj_merge(InfoList), + types = table_disj_merge(TypesList), + exported_types = sets_disj_merge(ExpTypesList), + contracts = table_disj_merge(ContractsList), + callbacks = table_disj_merge(CallbacksList) + }. + +group_fields(List) -> InfoList = [Info || #plt{info = Info} <- List], TypesList = [Types || #plt{types = Types} <- List], ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List], ContractsList = [Contracts || #plt{contracts = Contracts} <- List], - #plt{info = table_disj_merge(InfoList), - types = table_disj_merge(TypesList), - exported_types = sets_disj_merge(ExpTypesList), - contracts = table_disj_merge(ContractsList)}. + CallbacksList = [Callbacks || #plt{callbacks = Callbacks} <- List], + {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList}. -spec merge_plts_or_report_conflicts([file:filename()], [plt()]) -> plt(). @@ -329,7 +374,7 @@ find_duplicates(List) -> to_file(FileName, #plt{info = Info, types = Types, contracts = Contracts, - exported_types = ExpTypes}, + callbacks = Callbacks, exported_types = ExpTypes}, ModDeps, {MD5, OldModDeps}) -> NewModDeps = dict:merge(fun(_Key, OldVal, NewVal) -> ordsets:union(OldVal, NewVal) @@ -340,6 +385,7 @@ to_file(FileName, file_md5_list = MD5, info = Info, contracts = Contracts, + callbacks = Callbacks, types = Types, exported_types = ExpTypes, mod_deps = NewModDeps, diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index dc5a3fed37..4d86bb34a7 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -29,7 +29,7 @@ -export([analyze_callgraph/3, analyze_callgraph/4, - get_warnings/7]). + get_warnings/6]). %% These are only intended as debug functions. -export([doit/1, @@ -106,21 +106,19 @@ get_refined_success_typings(State) -> -type doc_plt() :: 'undefined' | dialyzer_plt:plt(). -spec get_warnings(dialyzer_callgraph:callgraph(), dialyzer_plt:plt(), doc_plt(), dialyzer_codeserver:codeserver(), set(), - pid(), boolean()) -> + pid()) -> {[dial_warning()], dialyzer_plt:plt(), doc_plt()}. -get_warnings(Callgraph, Plt, DocPlt, Codeserver, - NoWarnUnused, Parent, BehavioursChk) -> +get_warnings(Callgraph, Plt, DocPlt, Codeserver, NoWarnUnused, Parent) -> InitState = #st{callgraph = Callgraph, codeserver = Codeserver, no_warn_unused = NoWarnUnused, parent = Parent, plt = Plt}, NewState = get_refined_success_typings(InitState), Mods = dialyzer_callgraph:modules(NewState#st.callgraph), CWarns = dialyzer_contracts:get_invalid_contract_warnings(Mods, Codeserver, NewState#st.plt), - get_warnings_from_modules(Mods, NewState, DocPlt, BehavioursChk, CWarns). + get_warnings_from_modules(Mods, NewState, DocPlt, CWarns). -get_warnings_from_modules([M|Ms], State, DocPlt, - BehavioursChk, Acc) when is_atom(M) -> +get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) -> send_log(State#st.parent, io_lib:format("Getting warnings for ~w\n", [M])), #st{callgraph = Callgraph, codeserver = Codeserver, no_warn_unused = NoWarnUnused, plt = Plt} = State, @@ -135,19 +133,15 @@ get_warnings_from_modules([M|Ms], State, DocPlt, dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Records, NoWarnUnused), {NewAcc, Warnings2} = postprocess_dataflow_warns(RawWarnings2, State, Acc), Attrs = cerl:module_attrs(ModCode), - Warnings3 = if BehavioursChk -> - dialyzer_behaviours:check_callbacks(M, Attrs, - Plt, Codeserver); - true -> [] - end, + Warnings3 = dialyzer_behaviours:check_callbacks(M, Attrs, Plt, Codeserver), NewDocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt), NewCallgraph = dialyzer_callgraph:renew_race_info(Callgraph, RaceCode, PublicTables, NamedTables), State1 = st__renew_state_calls(NewCallgraph, State), - get_warnings_from_modules(Ms, State1, NewDocPlt, BehavioursChk, + get_warnings_from_modules(Ms, State1, NewDocPlt, [Warnings1, Warnings2, Warnings3|NewAcc]); -get_warnings_from_modules([], #st{plt = Plt}, DocPlt, _, Acc) -> +get_warnings_from_modules([], #st{plt = Plt}, DocPlt, Acc) -> {lists:flatten(Acc), Plt, DocPlt}. postprocess_dataflow_warns(RawWarnings, State, WarnAcc) -> @@ -476,7 +470,7 @@ doit(Module) -> {ok, Code} = dialyzer_utils:get_core_from_abstract_code(AbstrCode), {ok, Records} = dialyzer_utils:get_record_and_type_info(AbstrCode), %% contract typing info in dictionary format - {ok, Contracts} = + {ok, Contracts, _Callbacks} = dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)), AbstrCode, Records), Sigs0 = get_top_level_signatures(Code, Records, Contracts), diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index 30aec59d22..92868b6878 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -2161,13 +2161,21 @@ get_apply_constr(FunLabels, Dst, ArgTypes, #state{callgraph = CG} = State) -> case lists:member(error, MFAs) of true -> error; false -> - Constrs = [begin - State1 = state__new_constraint_context(State), - State2 = get_plt_constr(MFA, Dst, ArgTypes, State1), - state__cs(State2) - end || {ok, MFA} <- MFAs], - ApplyConstr = mk_disj_constraint_list(Constrs), - {ok, state__store_conj(ApplyConstr, State)} + Constrs0 = + [begin + State1 = state__new_constraint_context(State), + try get_plt_constr(MFA, Dst, ArgTypes, State1) of + State2 -> state__cs(State2) + catch + throw:error -> error + end + end || {ok, MFA} <- MFAs], + case [C || C <- Constrs0, C =/= error] of + [] -> throw(error); + Constrs -> + ApplyConstr = mk_disj_constraint_list(Constrs), + {ok, state__store_conj(ApplyConstr, State)} + end end. state__scc(#state{scc = SCC}) -> diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 12f8dec67e..2a248fb028 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -311,11 +311,15 @@ merge_records(NewRecords, OldRecords) -> %% %% ============================================================================ +-type spec_dict() :: dict(). +-type callback_dict() :: dict(). + -spec get_spec_info(atom(), abstract_code(), dict()) -> - {'ok', dict()} | {'error', string()}. + {'ok', spec_dict(), callback_dict()} | {'error', string()}. get_spec_info(ModName, AbstractCode, RecordsDict) -> - get_spec_info(AbstractCode, dict:new(), RecordsDict, ModName, "nofile"). + get_spec_info(AbstractCode, dict:new(), dict:new(), + RecordsDict, ModName, "nofile"). %% TypeSpec is a list of conditional contracts for a function. %% Each contract is of the form {[Argument], Range, [Constraint]} where @@ -323,21 +327,34 @@ get_spec_info(ModName, AbstractCode, RecordsDict) -> %% - Constraint is of the form {subtype, T1, T2} where T1 and T2 %% are erl_types:erl_type() -get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left], - SpecDict, RecordsDict, ModName, File) when is_list(TypeSpec) -> +get_spec_info([{attribute, Ln, Contract, {Id, TypeSpec}}|Left], + SpecDict, CallbackDict, RecordsDict, ModName, File) + when ((Contract =:= 'spec') or (Contract =:= 'callback')), + is_list(TypeSpec) -> MFA = case Id of {_, _, _} = T -> T; {F, A} -> {ModName, F, A} end, - try dict:find(MFA, SpecDict) of + ActiveDict = + case Contract of + spec -> SpecDict; + callback -> CallbackDict + end, + try dict:find(MFA, ActiveDict) of error -> - NewSpecDict = + NewActiveDict = dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, TypeSpec, - SpecDict, RecordsDict), - get_spec_info(Left, NewSpecDict, RecordsDict, ModName, File); + ActiveDict, RecordsDict), + {NewSpecDict, NewCallbackDict} = + case Contract of + spec -> {NewActiveDict, CallbackDict}; + callback -> {SpecDict, NewActiveDict} + end, + get_spec_info(Left, NewSpecDict, NewCallbackDict, + RecordsDict, ModName,File); {ok, {{OtherFile, L},_C}} -> {Mod, Fun, Arity} = MFA, - Msg = flat_format(" Contract for function ~w:~w/~w " + Msg = flat_format(" Contract/callback for function ~w:~w/~w " "already defined in ~s:~w\n", [Mod, Fun, Arity, OtherFile, L]), throw({error, Msg}) @@ -347,12 +364,14 @@ get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left], [Ln, Error])} end; get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left], - SpecDict, RecordsDict, ModName, _File) -> - get_spec_info(Left, SpecDict, RecordsDict, ModName, IncludeFile); -get_spec_info([_Other|Left], SpecDict, RecordsDict, ModName, File) -> - get_spec_info(Left, SpecDict, RecordsDict, ModName, File); -get_spec_info([], SpecDict, _RecordsDict, _ModName, _File) -> - {ok, SpecDict}. + SpecDict, CallbackDict, RecordsDict, ModName, _File) -> + get_spec_info(Left, SpecDict, CallbackDict, + RecordsDict, ModName, IncludeFile); +get_spec_info([_Other|Left], SpecDict, CallbackDict, + RecordsDict, ModName, File) -> + get_spec_info(Left, SpecDict, CallbackDict, RecordsDict, ModName, File); +get_spec_info([], SpecDict, CallbackDict, _RecordsDict, _ModName, _File) -> + {ok, SpecDict, CallbackDict}. %% ============================================================================ %% diff --git a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options new file mode 100644 index 0000000000..50991c9bc5 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options @@ -0,0 +1 @@ +{dialyzer_options, []}. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs new file mode 100644 index 0000000000..da498c225d --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs @@ -0,0 +1,5 @@ + +my_callbacks_wrong.erl:26: The return type #state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()} in the specification of callback_init/1 is not a subtype of {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour +my_callbacks_wrong.erl:28: The inferred return type of callback_init/1 (#state{parent::'undefined' | pid(),status::'init',subscribe::[],counter::1}) has nothing in common with {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour +my_callbacks_wrong.erl:30: The return type {'noreply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} | {'reply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of my_behaviour behaviour +my_callbacks_wrong.erl:39: The specified type for the 2nd argument of callback_call/3 (atom()) is not a supertype of pid(), which is expected type for this argument in the callback of the my_behaviour behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return new file mode 100644 index 0000000000..2afb5db133 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return @@ -0,0 +1,2 @@ + +gen_event_incorrect_return.erl:16: The inferred return type of init/1 ('error') has nothing in common with {'ok',_} | {'ok',_,'hibernate'}, which is the expected return type for the callback of gen_event behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args new file mode 100644 index 0000000000..3e98da785f --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args @@ -0,0 +1,8 @@ + +gen_server_incorrect_args.erl:3: Undefined callback function code_change/3 (behaviour 'gen_server') +gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') +gen_server_incorrect_args.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server') +gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour 'gen_server') +gen_server_incorrect_args.erl:3: Undefined callback function terminate/2 (behaviour 'gen_server') +gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of gen_server behaviour +gen_server_incorrect_args.erl:7: The inferred type for the 2nd argument of handle_call/3 ('boo' | 'foo') is not a supertype of {pid(),_}, which is expected type for this argument in the callback of the gen_server behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks new file mode 100644 index 0000000000..5e0ed5fd27 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks @@ -0,0 +1,3 @@ + +gen_server_missing_callbacks.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') +gen_server_missing_callbacks.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server') diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour new file mode 100644 index 0000000000..a38e662ccf --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour @@ -0,0 +1,9 @@ + +sample_callback_wrong.erl:15: The inferred return type of sample_callback_2/0 (42) has nothing in common with atom(), which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:16: The inferred return type of sample_callback_3/0 ('fair') has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:17: The inferred return type of sample_callback_4/1 ('fail') has nothing in common with 'ok', which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:19: The inferred return type of sample_callback_5/1 (string()) has nothing in common with 'fail' | 'ok', which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:19: The inferred type for the 1st argument of sample_callback_5/1 (atom()) is not a supertype of 1..255, which is expected type for this argument in the callback of the sample_behaviour behaviour +sample_callback_wrong.erl:21: The inferred return type of sample_callback_6/3 ({'okk',number()}) has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:21: The inferred type for the 3rd argument of sample_callback_6/3 (atom()) is not a supertype of string(), which is expected type for this argument in the callback of the sample_behaviour behaviour +sample_callback_wrong.erl:3: Undefined callback function sample_callback_1/0 (behaviour 'sample_behaviour') diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old new file mode 100644 index 0000000000..f0181bb59c --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old @@ -0,0 +1,4 @@ + +incorrect_args_callback.erl:12: The inferred type for the 2nd argument of bar/2 ('yes') is not a supertype of [any()], which is expected type for this argument in the callback of the correct_behaviour behaviour +incorrect_return_callback.erl:9: The inferred return type of foo/0 ('error') has nothing in common with 'no' | 'yes', which is the expected return type for the callback of correct_behaviour behaviour +missing_callback.erl:5: Undefined callback function foo/0 (behaviour 'correct_behaviour') diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return new file mode 100644 index 0000000000..e89caf3cf7 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return @@ -0,0 +1,2 @@ + +supervisor_incorrect_return.erl:14: The inferred return type of init/1 ({'ok',{{'one_against_one',0,1},[{_,_,_,_,_,_},...]}}) has nothing in common with 'ignore' | {'ok',{{'one_for_all',non_neg_integer(),non_neg_integer()} | {'one_for_one',non_neg_integer(),non_neg_integer()} | {'rest_for_one',non_neg_integer(),non_neg_integer()} | {'simple_one_for_one',non_neg_integer(),non_neg_integer()},[{_,{atom() | tuple(),atom(),'undefined' | [any()]},'permanent' | 'temporary' | 'transient','brutal_kill' | 'infinity' | non_neg_integer(),'supervisor' | 'worker','dynamic' | [atom() | tuple()]}]}}, which is the expected return type for the callback of supervisor behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks new file mode 100644 index 0000000000..7147ffc750 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks @@ -0,0 +1,2 @@ + +undefined_beh_callback.erl:5: Callback info about the undefined_behaviour behaviour is not available diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl new file mode 100644 index 0000000000..c4e5203448 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl @@ -0,0 +1,11 @@ +-module(my_behaviour). + +-callback callback_init(Parent :: pid()) -> {'ok', State::term()}. + +-callback callback_cast(State::term(), From::pid(), Msg::term()) -> + {'noreply', NewState::term()}. + +-callback callback_call(State::term(), From::pid(), Msg::term()) -> + {'reply', NewState::term(), Reply::term()}. + +-callback callback_exit(State::term()) -> 'ok'. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl new file mode 100644 index 0000000000..041b4ac56c --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl @@ -0,0 +1,59 @@ +-module(my_callbacks_correct). + +-export([ + callback_init/1 + , callback_call/3 + , callback_cast/3 + , callback_exit/1 + ]). + +-record(state, { + parent :: pid(), + status = init :: 'init' | 'open' | 'closed', + subscribe = [] :: list({pid(), integer()}), + counter = 1 :: integer() + }). + +-type state() :: #state{}. + +-type cast_message() :: 'open' | 'closed'. + +-type call_message() :: 'subscribe' | 'unsubscribe'. +-type call_reply() :: 'accepted' | 'rejected'. + +-spec callback_init(Parent::pid()) -> {'ok', state()}. + +callback_init(Parent) -> + {ok, #state{parent = Parent}}. + +-spec callback_cast(state(), pid(), cast_message()) -> {'noreply', state()}. + +callback_cast(#state{parent = Pid} = State, Pid, Message) + when Message =:= 'open'; Message =:= 'close' -> + {noreply, State#state{status = Message}}; +callback_cast(State, _Pid, _Message) -> + {noreply, State}. + +-spec callback_call(state(), pid(), call_message()) -> + {'reply', state(), call_reply()}. + +callback_call(#state{status = open, subscribe = Subscribers} = State, + Pid, Message) + when Message =:= 'subscribe'; + Message =:= 'unsubscribe' -> + NewState = + case Message of + subscribe -> + N = State#state.counter, + State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1}; + unsubscribe -> + State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)} + end, + {reply, NewState, accepted}; +callback_call(State, _Pid, _Message) -> + {reply, State, rejected}. + +-spec callback_exit(state()) -> 'ok'. + +callback_exit(_State) -> + ok. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl new file mode 100644 index 0000000000..0459622dc1 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl @@ -0,0 +1,61 @@ +-module(my_callbacks_wrong). + +-export([ + callback_init/1 + , callback_call/3 + , callback_cast/3 + , callback_exit/1 + ]). + +-behaviour(my_behaviour). + +-record(state, { + parent :: pid(), + status = init :: 'init' | 'open' | 'closed', + subscribe = [] :: list({pid(), integer()}), + counter = 1 :: integer() + }). + +-type state() :: #state{}. + +-type cast_message() :: 'open' | 'closed'. + +-type call_message() :: 'subscribe' | 'unsubscribe'. +-type call_reply() :: 'accepted' | 'rejected'. + +-spec callback_init(Parent::pid()) -> state(). %% Wrong return spec + +callback_init(Parent) -> #state{parent = Parent}. %% Wrong return + +-spec callback_cast(state(), pid() | atom(), cast_message()) -> + {'noreply' | 'reply', state()}. %% More generic spec + +callback_cast(#state{parent = Pid} = State, Pid, Message) + when Message =:= 'open'; Message =:= 'close' -> + {noreply, State#state{status = Message}}; +callback_cast(State, _Pid, _Message) -> + {noreply, State}. + +-spec callback_call(state(), atom(), call_message()) -> %% Wrong arg spec + {'reply', state(), call_reply()}. + +callback_call(#state{status = open, subscribe = Subscribers} = State, + Pid, Message) + when Message =:= 'subscribe'; + Message =:= 'unsubscribe' -> + NewState = + case Message of + subscribe -> + N = State#state.counter, + State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1}; + unsubscribe -> + State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)} + end, + {reply, NewState, accepted}; +callback_call(State, _Pid, _Message) -> + {reply, State, rejected}. + +-spec callback_exit(state()) -> ok. + +callback_exit(_State) -> + ok. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl new file mode 100644 index 0000000000..f5ccf7f8c4 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl @@ -0,0 +1,33 @@ +-module(gen_event_incorrect_return). + +-behaviour(gen_event). + +-export([start_link/0, add_handler/0]). + +-export([init/1, handle_event/2, handle_call/2, + handle_info/2, terminate/2, code_change/3]). + +start_link() -> + gen_event:start_link({local, myserver}). + +add_handler() -> + gen_event:add_handler(myserver, ?MODULE, []). + +init([]) -> + error. + +handle_event(_Event, State) -> + {ok, State}. + +handle_call(_Request, State) -> + Reply = ok, + {ok, Reply, State}. + +handle_info(_Info, State) -> + {ok, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl new file mode 100644 index 0000000000..df04dff80d --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl @@ -0,0 +1,11 @@ +-module(gen_server_incorrect_args). + +-behaviour(gen_server). + +-export([handle_call/3]). + +handle_call(_Request, From, _State) -> + case From of + 'boo' -> {'ok'}; + 'foo' -> {'no'} + end. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl new file mode 100644 index 0000000000..760466fdac --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl @@ -0,0 +1,23 @@ +-module(gen_server_missing_callbacks). + +-behaviour(gen_server). + +-export([start_link/0]). + +-export([init/1, handle_call/3, terminate/2, code_change/3]). + +start_link() -> + gen_server:start_link({local, myserver}, ?MODULE, [], []). + +init([]) -> + ignore. + +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl new file mode 100644 index 0000000000..116980986b --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl @@ -0,0 +1,13 @@ +-module(sample_behaviour). + +-type custom() :: 1..42. + +-callback sample_callback_1() -> term(). +-callback sample_callback_2() -> atom(). +-callback sample_callback_3() -> {'ok', custom()} | 'fail'. + +-callback sample_callback_4(term()) -> 'ok'. +-callback sample_callback_5(custom()) -> 'ok' | 'fail'. + +-callback sample_callback_6(custom(), custom(), string()) -> + {'ok', custom()} | 'fail'. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl new file mode 100644 index 0000000000..ab0378e6f0 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl @@ -0,0 +1,32 @@ +-module(sample_callback_correct). + +-behaviour(sample_behaviour). + +-export([ + sample_callback_1/0, + sample_callback_2/0, + sample_callback_3/0, + sample_callback_4/1, + sample_callback_5/1, + sample_callback_6/3 + ]). + +sample_callback_1() -> 42. % This is a valid return. +sample_callback_2() -> foo. % This is a valid return. +sample_callback_3() -> {ok, 17}. % This is a valid return. +sample_callback_4(Input) -> + put(mine, Input+1), % This is valid handling of the input + ok. % This is a valid return. +sample_callback_5(Input) -> + case Input - 1 < 22 of % This is valid handling of the input + true -> ok; % This is a valid return. + false -> fail % This is a valid return. + end. +sample_callback_6(OldNr, NewNr, Reason) -> + Diff = NewNr - OldNr, % This is valid handling of the input + Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input + case Diff > 0 of + true -> put(mine, {NewNr, Msg}), + {ok, NewNr}; % This is a valid return. + false -> fail % This is a valid return. + end. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl new file mode 100644 index 0000000000..c218174e58 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl @@ -0,0 +1,38 @@ +-module(sample_callback_correct_2). + +-behaviour(sample_behaviour). + +-export([ + sample_callback_1/0, + sample_callback_2/0, + sample_callback_3/0, + sample_callback_4/1, + sample_callback_5/1, + sample_callback_6/3, + common_infrastructure/1 + ]). + +sample_callback_1() -> 42. % This is a valid return. +sample_callback_2() -> halt(). % Crashes are also allowed. +sample_callback_3() -> {ok, 17}. % This is a valid return. +sample_callback_4(Input) -> + case Input of + 1 -> common_infrastructure(Input); % This is 'correct' input for + _ -> ok % common_infrastructure. + end. +sample_callback_5(Input) -> + case get(Input) of % This is valid handling of a more generic input + true -> ok; % This is a valid return. + false -> fail % This is a valid return. + end. +sample_callback_6(OldNr, NewNr, Reason) -> + Diff = NewNr - OldNr, % This is valid handling of the input + Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input + case Diff > 0 of + true -> put(mine, {NewNr, Msg}), + {ok, NewNr}; % This is a valid return. + false -> fail % This is a valid return. + end. + +common_infrastructure( 1) -> 'ok'; +common_infrastructure(42) -> 'fail'. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl new file mode 100644 index 0000000000..02a063fab7 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl @@ -0,0 +1,25 @@ +-module(sample_callback_wrong). + +-behaviour(sample_behaviour). + +-export([ +% sample_callback_1/0, + sample_callback_2/0, + sample_callback_3/0, + sample_callback_4/1, + sample_callback_5/1, + sample_callback_6/3 + ]). + +% sample_callback_1() -> 41. % We can't really break this contract so: missing! +sample_callback_2() -> 42. % This is not an atom(). +sample_callback_3() -> fair. % This is probably a typo. +sample_callback_4(_) -> % We cannot break the input. + fail. % We can definitely return a wrong value however. :) +sample_callback_5(Input) -> % Input is treated as an atom, result is a list. + atom_to_list(Input). % Both violate the contract. +sample_callback_6(OldNr, NewNr, Reason) -> + Diff = NewNr - OldNr, % This is valid handling of the input + %% Reason should have been treated as a string. + Msg = string:join(["Reason: ", atom_to_list(Reason)], ","), + {okk, NewNr}. %% This, too, is a typo. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl new file mode 100644 index 0000000000..90ce590997 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl @@ -0,0 +1,6 @@ +%%% This is a behaviour with info about its calllbacks. + +-module(correct_behaviour). + +-callback foo() -> yes | no. +-callback bar({atom(),_},[_]) -> term(). diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl new file mode 100644 index 0000000000..8f254520ab --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl @@ -0,0 +1,15 @@ +%%% This is a correct callback module for the correct_behaviour. + +-module(correct_callback). + +-behaviour(correct_behaviour). + +-export([foo/0, bar/2]). + +foo() -> + yes. + +bar({'query', 'boo'}, _Any) -> + no; +bar({'reply', [_R]}, [1,2,3]) -> + yes. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl new file mode 100644 index 0000000000..68fc60d418 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl @@ -0,0 +1,13 @@ +%%% This is a correct callback module for the correct_behaviour. + +-module(incorrect_args_callback). + +-behaviour(correct_behaviour). + +-export([foo/0, bar/2]). + +foo() -> + yes. + +bar({'reply', _Any}, yes) -> %% Should be a tuple and a list. + yes. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl new file mode 100644 index 0000000000..9ff920cdd0 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl @@ -0,0 +1,15 @@ +%%% This is a correct callback module for the correct_behaviour. + +-module(incorrect_return_callback). + +-behaviour(correct_behaviour). + +-export([foo/0, bar/2]). + +foo() -> + error. %% Should be 'yes' or 'no'. + +bar({'query', 'boo'}, _Any) -> + no; +bar({'reply', [_R]}, [1,2,3]) -> + yes. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl new file mode 100644 index 0000000000..e6c5306839 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl @@ -0,0 +1,10 @@ +%%% This is a correct callback module for the correct_behaviour. + +-module(missing_callback). + +-behaviour(correct_behaviour). + +-export([bar/2]). + +bar({'reply', _Any}, []) -> + yes. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl new file mode 100644 index 0000000000..616a9073ae --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl @@ -0,0 +1,17 @@ +-module(supervisor_incorrect_return). + +-behaviour(supervisor). + +-export([start_link/0]). + +-export([init/1]). + +-define(SERVER, ?MODULE). + +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +init([]) -> + AChild = {'AName',{'AModule',start_link,[]}, + permanent,2000,worker,['AModule']}, + {ok,{{one_against_one,0,1}, [AChild]}}. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl new file mode 100644 index 0000000000..8223225b4b --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl @@ -0,0 +1,13 @@ +%%% This is a correct callback module for the correct_behaviour. + +-module(undefined_beh_callback). + +-behaviour(undefined_behaviour). + +-export([foo/0, bar/2]). + +foo() -> + yes. + +bar({'reply', _Any}, yes) -> + yes. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl new file mode 100644 index 0000000000..fb3d4c5e03 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl @@ -0,0 +1,10 @@ +%%% This is a behaviour with undefined info about its calllbacks. + +-module(undefined_behaviour). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{foo, 0}, {bar, 2}]; +behaviour_info(_Other) -> + undefined. diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/crash b/lib/dialyzer/test/opaque_SUITE_data/results/crash index 6bdd934169..1ddae5149f 100644 --- a/lib/dialyzer/test/opaque_SUITE_data/results/crash +++ b/lib/dialyzer/test/opaque_SUITE_data/results/crash @@ -1,5 +1,4 @@ -crash_1.erl:42: The specification for crash_1:empty/0 states that the function might also return crash_1:targetlist() but the inferred return is none() crash_1.erl:45: Record construction #targetlist{list::[]} violates the declared type of field list::'undefined' | crash_1:target() crash_1.erl:48: The call crash_1:get_using_branch2(Branch::maybe_improper_list(),L::'undefined' | crash_1:target()) contains an opaque term as 2nd argument when terms of different types are expected in these positions crash_1.erl:50: The pattern <_Branch, []> can never match the type <maybe_improper_list(),'undefined' | crash_1:target()> diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets index 0177dcc88c..6b16dba2ff 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/inets +++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets @@ -3,14 +3,9 @@ ftp.erl:1243: The pattern {'ok', {N, Bytes}} can never match the type 'eof' | {' ftp.erl:640: The pattern {'closed', _Why} can never match the type 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'trans_neg_compl' | 'trans_no_space' | {'error' | 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'pos_prel' | 'trans_neg_compl' | 'trans_no_space',atom() | [any()] | {'invalid_server_response',[any(),...]}} http.erl:117: The pattern {'error', Reason} can never match the type #req_headers{connection::[45 | 97 | 101 | 105 | 107 | 108 | 112 | 118,...],content_length::[48,...],other::[{_,_}]} http.erl:138: Function close_session/2 will never be called -http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},port() | {'sslsocket',_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',port() | {'sslsocket',_,pid() | {_,{'config',_,_,_,_,{_,_,_,_}}} | {'sslsocket',_,pid() | {'sslsocket',_,pid() | {_,_,_}}}}) -http_lib.erl:415: The pattern 61 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} -http_lib.erl:417: The pattern 59 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} -http_lib.erl:420: The pattern 13 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} -http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} -http_lib.erl:428: Function read_chunk_ext_val/6 will never be called -http_lib.erl:444: The pattern 10 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} -http_lib.erl:552: Call to missing or unexported function ssl:accept/2 +http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',any()) +http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any() +http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any() http_lib.erl:99: Function getHeaderValue/2 will never be called httpc_handler.erl:660: Function exit_session_ok/2 has no local return httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}} @@ -26,14 +21,11 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo httpd_manager.erl:919: Function auth_status/1 will never be called httpd_manager.erl:926: Function sec_status/1 will never be called httpd_manager.erl:933: Function acceptor_status/1 will never be called -httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) -httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) -httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) -httpd_request_handler.erl:489: The variable Other can never match since previous clauses completely covered the type {'error',_} | {'ok','http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | {'http_request','DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),'*' | binary() | string() | {'abs_path',binary() | [any()]} | {'scheme',binary() | [any()],binary() | [any()]} | {'absoluteURI','http' | 'https',binary() | [any()],'undefined' | non_neg_integer(),binary() | [any()]},{non_neg_integer(),non_neg_integer()}} | {'http_response',{non_neg_integer(),non_neg_integer()},integer(),binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}} +httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()]) httpd_request_handler.erl:645: Function will never be called -httpd_socket.erl:129: Call to missing or unexported function ssl:accept/2 -httpd_socket.erl:49: The pattern {'ok', _} can never match the type {'error',_} httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_} httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_} httpd_sup.erl:92: The variable Else can never match since previous clauses completely covered the type {'ok',_,_} diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia index 2be71ac7d7..b397d37523 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia +++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia @@ -2,6 +2,7 @@ mnesia.erl:1319: Guard test size(Spec::[{_,_,_},...]) can never succeed mnesia.erl:1498: The call mnesia:bad_info_reply(Tab::atom(),Item::'type') will never return since it differs in the 2nd argument from the success typing arguments: (atom(),'memory' | 'size') mnesia.erl:331: Function mod2abs/1 has no local return +mnesia_backup.erl:49: Callback info about the mnesia_backup behaviour is not available mnesia_bup.erl:111: The created fun has no local return mnesia_bup.erl:574: Function fallback_receiver/2 has no local return mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return @@ -12,9 +13,12 @@ mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can neve mnesia_controller.erl:1685: The pattern {'noreply', State2, _Timeout} can never match the type {'reply',_,_} mnesia_event.erl:77: The pattern 'remove_handler' can never match the type {'ok',_} mnesia_event.erl:79: The pattern {'swap_handler', Args1, State1, Mod2, Args2} can never match the type {'ok',_} +mnesia_frag.erl:26: Callback info about the mnesia_access behaviour is not available mnesia_frag.erl:294: The call mnesia_frag:remote_collect(Ref::reference(),{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()])) mnesia_frag.erl:304: The call mnesia_frag:remote_collect(Ref::reference(),{'error',{'node_not_running',_}},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()])) mnesia_frag.erl:312: The call mnesia_frag:remote_collect(Ref::reference(),LocalRes::{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()])) +mnesia_frag_hash.erl:24: Callback info about the mnesia_frag_hash behaviour is not available +mnesia_frag_old_hash.erl:23: Callback info about the mnesia_frag_hash behaviour is not available mnesia_index.erl:52: The call mnesia_lib:other_val(Var::{_,'commit_work' | 'index' | 'setorbag' | 'storage_type' | {'index',_}},_ReASoN_::any()) will never return since it differs in the 1st argument from the success typing arguments: ({_,'active_replicas' | 'where_to_read' | 'where_to_write'},any()) mnesia_lib.erl:1028: The pattern {'EXIT', Reason} can never match the type [any()] | {'error',_} mnesia_lib.erl:957: The pattern {'ok', {0, _}} can never match the type 'eof' | {'error',atom()} | {'ok',binary() | string()} diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy new file mode 100644 index 0000000000..7ce440a60d --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy @@ -0,0 +1,4 @@ + +higher_order_discrepancy.erl:11: The call higher_order_discrepancy:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar') +higher_order_discrepancy.erl:14: Function g/1 has no local return +higher_order_discrepancy.erl:14: The pattern 'bar' can never match the type 'foo' diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2 b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2 new file mode 100644 index 0000000000..c1c7dbbfcc --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2 @@ -0,0 +1,8 @@ + +higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:f('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar') +higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('baz') +higher_order_discrepancy_2.erl:13: Function f/1 has no local return +higher_order_discrepancy_2.erl:13: The pattern 'bar' can never match the type 'foo' +higher_order_discrepancy_2.erl:14: Function g/1 has no local return +higher_order_discrepancy_2.erl:14: The pattern 'baz' can never match the type 'foo' +higher_order_discrepancy_2.erl:5: Function test/1 has no local return diff --git a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash index 191d3d4173..8c9df56a4b 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash +++ b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash @@ -12,4 +12,3 @@ tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary-unit:8>> can never match the type <<_:8>> tuple_set_crash.erl:62: The pattern {'play_list', _Playlist} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]} tuple_set_crash.erl:64: The pattern {'error', 17} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]} -tuple_set_crash.erl:83: The specification for tuple_set_crash:parse_message/1 states that the function might also return {'media_item_url_reply',integer(),binary()} but the inferred return is 'ok' | {'audio_device_info' | 'audio_output_info' | 'audio_target_info' | 'device_properties' | 'error' | 'video_device_info' | 'video_output_info' | 'video_target_info',[{'address' | 'audio_volume' | 'controller_description' | 'controller_name' | 'controller_status' | 'device_id' | 'display_type' | 'fw_version' | 'master_volume' | 'model' | 'output_id' | 'status' | 'target_id',binary() | non_neg_integer()}] | 1..255} diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl new file mode 100644 index 0000000000..ff5ee6bac4 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl @@ -0,0 +1,14 @@ +-module(higher_order_discrepancy). + +-export([test/1]). + +test(X) -> + F = + case X of + 1 -> fun f/1; + 2 -> fun g/1 + end, + F(foo). + +f(foo) -> ok. +g(bar) -> ok. diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl new file mode 100644 index 0000000000..4b0d4f6b45 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl @@ -0,0 +1,14 @@ +-module(higher_order_discrepancy_2). + +-export([test/1]). + +test(X) -> + F = + case X of + 1 -> fun f/1; + 2 -> fun g/1 + end, + F(foo). + +f(bar) -> ok. +g(baz) -> ok. diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile index 1453138cb6..bc3e649e6b 100644 --- a/lib/diameter/doc/src/Makefile +++ b/lib/diameter/doc/src/Makefile @@ -126,8 +126,6 @@ debug opt: info: @echo "->Makefile<-" @echo "" - @echo "DOCSUPPORT = $(DOCSUPPORT)" - @echo "" @echo "INDEX_FILE = $(INDEX_FILE)" @echo "INDEX_SRC = $(INDEX_SRC)" @echo "INDEX_TARGET = $(INDEX_TARGET)" @@ -141,10 +139,6 @@ info: @echo "" @echo "GIF_FILES = $(GIF_FILES)" @echo "" - @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)" - @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)" - @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)" - @echo "" @echo "MAN1_FILES = $(MAN1_FILES)" @echo "MAN3_FILES = $(MAN3_FILES)" @echo "MAN4_FILES = $(MAN4_FILES)" diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 43c497f50a..2d8edb1301 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -431,7 +431,7 @@ eval(F) -> </code> <p> -Evaluating an evaluable() <c>E</c> on an argument list <c>A</c> +Applying an evaluable() <c>E</c> to an argument list <c>A</c> is meant in the sense of <c>eval([E|A])</c>.</p> <p> @@ -565,7 +565,7 @@ Pkt = #diameter_packet{} </code> <p> -Reports that the RFC 3539 watchdog state machine has +The RFC 3539 watchdog state machine has transitioned into (<c>up</c>) or out of (<c>down</c>) the open state. If a <c>diameter_packet</c> record is present in an <c>up</c> tuple @@ -576,9 +576,9 @@ connectivity.</p> <p> Note that a single up/down event for a given peer corresponds to -as many peer_up/down callbacks as there are Diameter -applications shared by the peer, as determined during capablilities -exchange. +as many <seealso marker="diameter_app#peer_up">peer_up/peer_down</seealso> +callbacks as there are Diameter applications shared by the peer, +as determined during capablilities exchange. That is, the event communicates connectivity with the peer as a whole while the callbacks communicate connectivity with respect to individual Diameter applications.</p> @@ -597,12 +597,96 @@ transport connection with a peer following <c>reconnect_timer</c> or <c>watchdog_timer</c> expiry.</p> </item> +<tag><c>{closed, Ref, Reason, Config}</c></tag> +<item> +<code> +Ref = transport_ref() +Config = {connect|listen, [transport_opt()]} +</code> + +<p> +Capabilities exchange has failed. <c>Reason</c> can be one of +the following.</p> + +<taglist> + +<tag><c>{'CER', Result, Caps, Pkt}</c></tag> +<item> +<code> +Result = ResultCode | {capabilities_cb, CB, ResultCode|discard} +Caps = #diameter_caps{} +Pkt = #diameter_packet{} +ResultCode = integer() +CB = evaluable() +</code> + +<p> +An incoming CER has been answered with the indicated result code or +discarded. +The capabilities record contains pairs of values for the the local +node and remote peer. +The packet record contains the CER in question. +In the case of rejection by a capabilities callback, the tuple +indicates the rejecting callback.</p> +</item> + +<tag><c>{'CER', Caps, {ResultCode, Pkt}}</c></tag> +<item> +<code> +ResultCode = integer() +Caps = #diameter_caps{} +Pkt = #diameter_packet{} +</code> + +<p> +An incoming CER contained errors and has been answered with the +indicated result code. +The capabilities record contains only values for the the local +node. +The packet record contains the CER in question.</p> +</item> + +<tag><c>{'CEA', Result, Caps, Pkt}</c></tag> +<item> +<code> +Result = integer() | atom() | {capabilities_cb, CB, ResultCode|discard} +Caps = #diameter_caps{} +Pkt = #diameter_packet{} +ResultCode = integer() +</code> + +<p> +An incoming CEA has been rejected for the indicated reason. +An integer-valued <c>Result</c> indicates the result code sent +by the peer. +The capabilities record contains pairs of values for the the local +node and remote peer. +The packet record contains the CEA in question. +In the case of rejection by a capabilities callback, the tuple +indicates the rejecting callback.</p> +</item> + +<tag><c>{'CEA', Caps, Pkt}</c></tag> +<item> +<code> +Caps = #diameter_caps{} +Pkt = #diameter_packet{} +</code> + +<p> +An incoming CER contained errors and has been rejected. +The capabilities record contains only values for the the local node. +The packet record contains the CEA in question.</p> +</item> + +</taglist> +</item> + </taglist> <p> For forward compatibility, a subscriber should be prepared to receive -<c>diameter_event.info</c> of forms other than those documented -above.</p> +info fields of forms other than the above.</p> <marker id="service_name"/> </item> @@ -706,6 +790,31 @@ not over SCTP as implemented by <seealso marker="diameter_sctp">diameter_sctp(3)</seealso>.</p> </item> +<tag><c>{capabilities_cb, evaluable()}</c></tag> +<item> +<p> +A callback invoked upon reception of CER/CEA during capabilities +exchange in order to ask whether or not the connection should +be accepted. +Applied to the transport reference (as returned by <seealso +marker="#add_transport">add_transport/2</seealso>) and +<c>diameter_caps</c> record of the connection. +Returning <c>ok</c> accepts the connection. +Returning <c>integer()</c> causes an incoming +CER to be answered with the specified Result-Code. +Returning <c>discard</c> causes an incoming CER to +be discarded. +Returning <c>unknown</c> is equivalent to returning <c>3010</c>, +DIAMETER_UNKNOWN_PEER. +Returning anything but <c>ok</c> or a 2xxx series result +code causes the transport connection to be broken.</p> + +<p> +Multiple <c>capabilities_cb</c> options can be specified, in which +case the corresponding callbacks are applied until either all return +<c>ok</c> or one does not.</p> +</item> + <tag><c>{watchdog_timer, TwInit}</c></tag> <item> <code> diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index d037e1044a..13a6c462af 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -40,14 +40,14 @@ encode_avps(Name, Rec) -> list_to_binary(encode(Name, Rec)) catch throw: {?MODULE, Reason} -> - diameter_dbg:log({encode, error}, + diameter_lib:log({encode, error}, ?MODULE, ?LINE, {Reason, Name, Rec}), erlang:error(list_to_tuple(Reason ++ [Name])); error: Reason -> Stack = erlang:get_stacktrace(), - diameter_dbg:log({encode, failure}, + diameter_lib:log({encode, failure}, ?MODULE, ?LINE, {Reason, Name, Rec, Stack}), @@ -159,7 +159,7 @@ d_rc(Name, {Avps, {Rec, [] = Failed}}) -> {Rec, Avps, Failed} catch throw: {?MODULE, {AvpName, Reason}} -> - diameter_dbg:log({decode, error}, + diameter_lib:log({decode, error}, ?MODULE, ?LINE, {AvpName, Reason, Rec}), @@ -260,7 +260,7 @@ d(Name, Avp, {Avps, Acc}) -> %% respond sensibly to. Log the occurence for traceability, %% but the peer will also receive info in the resulting %% answer-message. - diameter_dbg:log({decode, failure}, + diameter_lib:log({decode, failure}, ?MODULE, ?LINE, {Reason, Avp, erlang:get_stacktrace()}), diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in index 6318f2bc9c..cd3c297d75 100644 --- a/lib/diameter/make/rules.mk.in +++ b/lib/diameter/make/rules.mk.in @@ -112,8 +112,6 @@ $(EBIN)/%.beam: $(ESRC)/%.erl # ---------------------------------------------------- # export VSN -# DOCSUPPORT = 1 - # TOPDOCDIR=../../../../doc DOCDIR = .. diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index a057632d15..eea2aa894d 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -177,7 +177,7 @@ else include $(ERL_TOP)/make/otp_release_targets.mk endif -# Can't $(INSTALL_DIR) more than on directory at a time on Solaris. +# Can't $(INSTALL_DIR) more than one directory at a time on Solaris. release_spec: opt for d in bin ebin examples include src/dict $(TARGET_DIRS:%/=src/%); do \ @@ -209,7 +209,7 @@ gen/diameter_gen_base_accounting.hrl gen/diameter_gen_relay.hrl: \ gen/diameter_gen_base_rfc3588.erl gen/diameter_gen_base_rfc3588.hrl: \ $(COMPILER_MODULES:compiler/%=$(EBIN)/%.$(EMULATOR)) -$(DICT_MODULES:%=$(EBIN)/%.$(EMULATOR)): \ +$(DICT_MODULES:gen/%=$(EBIN)/%.$(EMULATOR)): \ $(INCDIR)/diameter.hrl \ $(INCDIR)/diameter_gen.hrl diff --git a/lib/diameter/src/base/diameter.appup.src b/lib/diameter/src/base/diameter.appup.src index 6d8ceadb92..b1c94d4cc8 100644 --- a/lib/diameter/src/base/diameter.appup.src +++ b/lib/diameter/src/base/diameter.appup.src @@ -20,28 +20,11 @@ {"%VSN%", [ - {"0.9", - [ - {load_module, diameter, soft_purge, soft_purge, []}, - {load_module, diameter_capx, soft_purge, soft_purge, []}, - {load_module, diameter_codec, soft_purge, soft_purge, [diameter_lib]}, - {load_module, diameter_lib, soft_purge, soft_purge, []}, - {load_module, diameter_types, soft_purge, soft_purge, []}, - {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []}, - {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []}, - {load_module, diameter_gen_relay, soft_purge, soft_purge, []}, - {update, diameter_service, soft, soft_purge, soft_purge, [diameter_lib]}, - {update, diameter_config, soft, soft_purge, soft_purge, []}, - {update, diameter_peer, soft, soft_purge, soft_purge, []}, - {update, diameter_peer_fsm, soft, soft_purge, soft_purge, [diameter_lib]}, - {update, diameter_reg, soft, soft_purge, soft_purge, []}, - {update, diameter_sctp, soft, soft_purge, soft_purge, []}, - {update, diameter_stats, soft, soft_purge, soft_purge, []}, - {update, diameter_sync, soft, soft_purge, soft_purge, []}, - {update, diameter_watchdog, soft, soft_purge, soft_purge, [diameter_lib]} - ] - } + {"0.9", [{restart_application, diameter}]}, + {"0.10", [{restart_application, diameter}]} ], [ + {"0.9", [{restart_application, diameter}]}, + {"0.10", [{restart_application, diameter}]} ] }. diff --git a/lib/diameter/src/base/diameter_capx.erl b/lib/diameter/src/base/diameter_capx.erl index 138e76411e..842a9e6103 100644 --- a/lib/diameter/src/base/diameter_capx.erl +++ b/lib/diameter/src/base/diameter_capx.erl @@ -57,9 +57,9 @@ -include("diameter_types.hrl"). -include("diameter_gen_base_rfc3588.hrl"). --define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). --define(NOAPP, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_APPLICATION'). --define(NOSECURITY, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_SECURITY'). +-define(SUCCESS, 2001). %% DIAMETER_SUCCESS +-define(NOAPP, 5010). %% DIAMETER_NO_COMMON_APPLICATION +-define(NOSECURITY, 5017). %% DIAMETER_NO_COMMON_SECURITY -define(NO_INBAND_SECURITY, 0). -define(TLS, 1). @@ -96,7 +96,7 @@ try_it([Fun | Args]) -> try apply(Fun, Args) of T -> {ok, T} catch - throw: ?FAILURE(Reason) -> {error, {Reason, Args}} + throw: ?FAILURE(Reason) -> {error, Reason} end. %% mk_caps/2 @@ -224,10 +224,6 @@ rCER(CER, #diameter_service{capabilities = LCaps} = Svc) -> RCaps, CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS})}. -%% TODO: 5.3 of RFC 3588 says we MUST return DIAMETER_NO_COMMON_APPLICATION -%% in the CEA and SHOULD disconnect the transport. However, we have -%% no way to guarantee the send before disconnecting. - build_CEA([], _, _, CEA) -> CEA#diameter_base_CEA{'Result-Code' = ?NOAPP}; @@ -292,25 +288,12 @@ to_cea(CER, Field, CEA) -> %% rCEA/2 -rCEA(#diameter_base_CEA{'Result-Code' = RC} - = CEA, - #diameter_service{capabilities = LCaps} - = Svc) -> - RC == ?SUCCESS orelse ?THROW({'Result-Code', RC}), - +rCEA(CEA, #diameter_service{capabilities = LCaps} = Svc) -> RCaps = capx_to_caps(CEA), SApps = common_applications(LCaps, RCaps, Svc), - - [] == SApps andalso ?THROW(no_common_applications), - IS = common_security(LCaps, RCaps), - [] == IS andalso ?THROW(no_common_security), - - {SApps, IS, RCaps}; - -rCEA(CEA, _Svc) -> - ?THROW({invalid, CEA}). + {SApps, IS, RCaps}. %% capx_to_caps/1 diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index d88f42fb7c..fe1212b7e0 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -190,26 +190,13 @@ encode_avps(Avps) -> %% msg_header/3 -msg_header(Mod, MsgName, Header) -> - {Code, Flags, ApplId} = h(Mod, MsgName, Header), - {Code, p(Flags, Header), ApplId}. - -%% 6.2 of 3588 requires the same 'P' bit on an answer as on the -%% request. - -p(Flags, #diameter_header{is_request = true, - is_proxiable = P}) -> - Flags band (2#10110000 bor choose(P, 2#01000000, 0)); -p(Flags, _) -> - Flags. - -h(Mod, 'answer-message' = MsgName, Header) -> +msg_header(Mod, 'answer-message' = MsgName, Header) -> ?BASE = Mod, #diameter_header{cmd_code = Code} = Header, {_, Flags, ApplId} = ?BASE:msg_header(MsgName), {Code, Flags, ApplId}; -h(Mod, MsgName, _) -> +msg_header(Mod, MsgName, _) -> Mod:msg_header(MsgName). %% rec2msg/2 @@ -554,8 +541,3 @@ pack_avp(Code, Flags, Vid, Sz, Bin) -> pack_avp(Code, Flags, Sz, Bin) -> Length = Sz + 8, <<Code:32, Flags:8, Length:24, Bin/binary>>. - -%% =========================================================================== - -choose(true, X, _) -> X; -choose(false, _, X) -> X. diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index 282fa2742f..fae5d763dc 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -55,7 +55,8 @@ -define(NO_INBAND_SECURITY, 0). -define(TLS, 1). --define(LOOP_TIMEOUT, 2000). +%% A 2xxx series Result-Code. Not necessarily 2001. +-define(IS_SUCCESS(N), 2 == (N) div 1000). %% RFC 3588: %% @@ -142,9 +143,12 @@ init(T) -> proc_lib:init_ack({ok, self()}), gen_server:enter_loop(?MODULE, [], i(T)). -i({WPid, {M, _} = T, Opts, #diameter_service{capabilities = Caps} = Svc0}) -> +i({WPid, T, Opts, #diameter_service{capabilities = Caps} = Svc0}) -> putr(dwa, dwa(Caps)), - {ok, TPid, Svc} = start_transport(T, Opts, Svc0), + {M, Ref} = T, + {[Ts], Rest} = proplists:split(Opts, [capabilities_cb]), + putr(capabilities_cb, {Ref, [F || {_,F} <- Ts]}), + {ok, TPid, Svc} = start_transport(T, Rest, Svc0), erlang:monitor(process, TPid), erlang:monitor(process, WPid), #state{parent = WPid, @@ -198,10 +202,13 @@ handle_info(T, #state{} = State) -> ?LOG(stop, T), x(T, State) catch - throw: {?MODULE, Tag, Reason} -> + {?MODULE, Tag, Reason} -> ?LOG(Tag, {Reason, T}), {stop, {shutdown, Reason}, State} end. +%% The form of the exception caught here is historical. It's +%% significant that it's not a 2-tuple, as in ?FAILURE(Reason), +%% since these are caught elsewhere. x(Reason, #state{} = S) -> close_wd(Reason, S), @@ -226,6 +233,9 @@ putr(Key, Val) -> getr(Key) -> get({?MODULE, Key}). +eraser(Key) -> + erase({?MODULE, Key}). + %% transition/2 %% Connection to peer. @@ -316,9 +326,10 @@ send_CER(#state{mode = {connect, Remote}, service = #diameter_service{capabilities = Caps}, transport = TPid} = S) -> - req_send_CER(Caps#diameter_caps.origin_host, Remote) + OH = Caps#diameter_caps.origin_host, + req_send_CER(OH, Remote) orelse - close(connected, S), + close({already_connected, Remote, Caps}, S), CER = build_CER(S), ?LOG(send, 'CER'), send(TPid, encode(CER)), @@ -460,20 +471,20 @@ handle_request(Type, #diameter_packet{} = Pkt, S) -> %% send_answer/3 send_answer(Type, ReqPkt, #state{transport = TPid} = S) -> - #diameter_packet{header = #diameter_header{version = V, - end_to_end_id = Eid, - hop_by_hop_id = Hid, - is_proxiable = P}, + #diameter_packet{header = H, transport_data = TD} = ReqPkt, - {Answer, PostF} = build_answer(Type, V, ReqPkt, S), + {Msg, PostF} = build_answer(Type, ReqPkt, S), - Pkt = #diameter_packet{header = #diameter_header{version = V, - end_to_end_id = Eid, - hop_by_hop_id = Hid, - is_proxiable = P}, - msg = Answer, + %% An answer message clears the R and T flags and retains the P + %% flag. The E flag is set at encode. + Pkt = #diameter_packet{header + = H#diameter_header{version = ?DIAMETER_VERSION, + is_request = false, + is_error = undefined, + is_retransmitted = false}, + msg = Msg, transport_data = TD}, send(TPid, diameter_codec:encode(?BASE, Pkt)), @@ -484,56 +495,104 @@ eval([F|A], S) -> eval(ok, S) -> S. -%% build_answer/4 +%% build_answer/3 build_answer('CER', - ?DIAMETER_VERSION, #diameter_packet{msg = CER, - header = #diameter_header{is_error = false}, + header = #diameter_header{version + = ?DIAMETER_VERSION, + is_error = false}, errors = []} = Pkt, - #state{service = Svc} - = S) -> - #diameter_service{capabilities = #diameter_caps{origin_host = OH}} - = Svc, - - {SupportedApps, - #diameter_caps{origin_host = DH} = RCaps, - #diameter_base_CEA{'Result-Code' = RC} - = CEA} + S) -> + {SupportedApps, RCaps, #diameter_base_CEA{'Result-Code' = RC, + 'Inband-Security-Id' = IS} + = CEA} = recv_CER(CER, S), + #diameter_caps{origin_host = {OH, DH}} + = Caps + = capz(caps(S), RCaps), + try 2001 == RC %% DIAMETER_SUCCESS - orelse ?THROW({sent_CEA, RC}), + orelse ?THROW(RC), register_everywhere({?MODULE, connection, OH, DH}) - orelse ?THROW({election_lost, 4003}), - #diameter_base_CEA{'Inband-Security-Id' = [IS]} - = CEA, - {CEA, [fun open/5, Pkt, SupportedApps, RCaps, {accept, IS}]} + orelse ?THROW(4003), %% DIAMETER_ELECTION_LOST + caps_cb(Caps) + of + N -> {cea(CEA, N), [fun open/5, Pkt, + SupportedApps, + Caps, + {accept, hd([_] = IS)}]} catch - ?FAILURE({Reason, RC}) -> - {answer('CER', S) ++ [{'Result-Code', RC}], - [fun close/2, {'CER', Reason, DH}]} + ?FAILURE(Reason) -> + rejected(Reason, {'CER', Reason, Caps, Pkt}, S) end; %% The error checks below are similar to those in diameter_service for %% other messages. Should factor out the commonality. -build_answer(Type, V, #diameter_packet{header = H, errors = Es} = Pkt, S) -> - FailedAvp = failed_avp([A || {_,A} <- Es]), - Ans = answer(answer(Type, S), V, H, Es), - {set(Ans, FailedAvp), if 'CER' == Type -> - [fun close/2, {Type, V, Pkt}]; - true -> - ok - end}. +build_answer(Type, + #diameter_packet{header = H, + errors = Es} + = Pkt, + S) -> + RC = rc(H, Es), + {answer(Type, RC, Es, S), post(Type, RC, Pkt, S)}. + +cea(CEA, ok) -> + CEA; +cea(CEA, 2001) -> + CEA; +cea(CEA, RC) -> + CEA#diameter_base_CEA{'Result-Code' = RC}. + +post('CER' = T, RC, Pkt, S) -> + [fun close/2, {T, caps(S), {RC, Pkt}}]; +post(_, _, _, _) -> + ok. + +rejected({capabilities_cb, _F, Reason}, T, S) -> + rejected(Reason, T, S); + +rejected(discard, T, S) -> + close(T, S); +rejected({N, Es}, T, S) -> + {answer('CER', N, Es, S), [fun close/2, T]}; +rejected(N, T, S) -> + rejected({N, []}, T, S). + +answer(Type, RC, Es, S) -> + set(answer(Type, RC, S), failed_avp([A || {_,A} <- Es])). + +answer(Type, RC, S) -> + answer_message(answer(Type, S), RC). +%% answer_message/2 + +answer_message([_ | Avps], RC) + when 3000 =< RC, RC < 4000 -> + ['answer-message', {'Result-Code', RC} + | lists:filter(fun is_origin/1, Avps)]; + +answer_message(Msg, RC) -> + Msg ++ [{'Result-Code', RC}]. + +is_origin({N, _}) -> + N == 'Origin-Host' + orelse N == 'Origin-Realm' + orelse N == 'Origin-State-Id'. + +%% failed_avp/1 + failed_avp([] = No) -> No; failed_avp(Avps) -> [{'Failed-AVP', [[{'AVP', Avps}]]}]. +%% set/2 + set(Ans, []) -> Ans; set(['answer-message' | _] = Ans, FailedAvp) -> @@ -541,18 +600,22 @@ set(['answer-message' | _] = Ans, FailedAvp) -> set([_|_] = Ans, FailedAvp) -> Ans ++ FailedAvp. -answer([_, OH, OR | _], _, #diameter_header{is_error = true}, _) -> - ['answer-message', OH, OR, {'Result-Code', 3008}]; +%% rc/2 + +rc(#diameter_header{is_error = true}, _) -> + 3008; %% DIAMETER_INVALID_HDR_BITS -answer([_, OH, OR | _], _, _, [Bs|_]) +rc(_, [Bs|_]) when is_bitstring(Bs) -> - ['answer-message', OH, OR, {'Result-Code', 3009}]; + 3009; %% DIAMETER_INVALID_HDR_BITS -answer(Ans, ?DIAMETER_VERSION, _, Es) -> - Ans ++ [{'Result-Code', rc(Es)}]; +rc(#diameter_header{version = ?DIAMETER_VERSION}, Es) -> + rc(Es); -answer(Ans, _, _, _) -> - Ans ++ [{'Result-Code', 5011}]. %% DIAMETER_UNSUPPORTED_VERSION +rc(_, _) -> + 5011. %% DIAMETER_UNSUPPORTED_VERSION + +%% rc/1 rc([]) -> 2001; %% DIAMETER_SUCCESS @@ -595,12 +658,14 @@ a('CER', #diameter_caps{vendor_id = Vid, origin_host = Host, origin_realm = Realm, host_ip_address = Addrs, - product_name = Name}) -> + product_name = Name, + origin_state_id = OSI}) -> ['CEA', {'Origin-Host', Host}, {'Origin-Realm', Realm}, {'Host-IP-Address', Addrs}, {'Vendor-Id', Vid}, - {'Product-Name', Name}]; + {'Product-Name', Name}, + {'Origin-State-Id', OSI}]; a('DPR', #diameter_caps{origin_host = Host, origin_realm = Realm}) -> @@ -615,27 +680,25 @@ recv_CER(CER, #state{service = Svc}) -> %% handle_CEA/1 -handle_CEA(#diameter_packet{header = #diameter_header{version = V}, - bin = Bin} +handle_CEA(#diameter_packet{bin = Bin} = Pkt, #state{service = #diameter_service{capabilities = LCaps}} = S) when is_binary(Bin) -> ?LOG(recv, 'CEA'), - ?DIAMETER_VERSION == V orelse close({version, V}, S), - - #diameter_packet{msg = CEA, errors = Errors} + #diameter_packet{msg = CEA} = DPkt = diameter_codec:decode(?BASE, Pkt), - [] == Errors orelse close({errors, Errors}, S), + {SApps, IS, RCaps} = recv_CEA(DPkt, S), - {SApps, [IS], #diameter_caps{origin_host = DH} = RCaps} - = recv_CEA(CEA, S), + #diameter_caps{origin_host = {OH, DH}} + = Caps + = capz(LCaps, RCaps), - #diameter_caps{origin_host = OH} - = LCaps, + #diameter_base_CEA{'Result-Code' = RC} + = CEA, %% Ensure that we don't already have a connection to the peer in %% question. This isn't the peer election of 3588 except in the @@ -643,60 +706,101 @@ handle_CEA(#diameter_packet{header = #diameter_header{version = V}, %% receive a CER/CEA, the first that arrives wins the right to a %% connection with the peer. - register_everywhere({?MODULE, connection, OH, DH}) - orelse close({'CEA', DH}, S), - - open(DPkt, SApps, RCaps, {connect, IS}, S). + try + ?IS_SUCCESS(RC) + orelse ?THROW(RC), + [] == SApps + andalso ?THROW(no_common_application), + [] == IS + andalso ?THROW(no_common_security), + register_everywhere({?MODULE, connection, OH, DH}) + orelse ?THROW(election_lost), + caps_cb(Caps) + of + _ -> open(DPkt, SApps, Caps, {connect, hd([_] = IS)}, S) + catch + ?FAILURE(Reason) -> close({'CEA', Reason, Caps, DPkt}, S) + end. +%% Check more than the result code since the peer could send success +%% regardless. If not 2001 then a peer_up callback could do anything +%% required. It's not unimaginable that a peer agreeing to TLS after +%% capabilities exchange could send DIAMETER_LIMITED_SUCCESS = 2002, +%% even if this isn't required by RFC 3588. %% recv_CEA/2 -recv_CEA(CEA, #state{service = Svc} = S) -> - case diameter_capx:recv_CEA(CEA, Svc) of - {ok, {_,_}} -> %% return from old code - close({'CEA', update}, S); - {ok, {[], _, _}} -> - close({'CEA', no_common_application}, S); - {ok, {_, [], _}} -> - close({'CEA', no_common_security}, S); - {ok, {_,_,_} = T} -> - T; - {error, Reason} -> - close({'CEA', Reason}, S) +recv_CEA(#diameter_packet{header = #diameter_header{version + = ?DIAMETER_VERSION, + is_error = false}, + msg = CEA, + errors = []}, + #state{service = Svc}) -> + {ok, T} = diameter_capx:recv_CEA(CEA, Svc), + T; + +recv_CEA(Pkt, S) -> + close({'CEA', caps(S), Pkt}, S). + +caps(#diameter_service{capabilities = Caps}) -> + Caps; +caps(#state{service = Svc}) -> + caps(Svc). + +%% caps_cb/1 + +caps_cb(Caps) -> + {Ref, Ts} = eraser(capabilities_cb), + ccb(Ts, [Ref, Caps]). + +ccb([], _) -> + ok; +ccb([F | Rest], T) -> + case diameter_lib:eval([F|T]) of + ok -> + ccb(Rest, T); + N when ?IS_SUCCESS(N) -> %% 2xxx result code: accept immediately + N; + Res -> + ?THROW({capabilities_cb, F, rejected(Res)}) end. +%% Note that returning 2xxx causes the capabilities exchange to be +%% accepted directly, without further callbacks. + +rejected(discard = T) -> + T; +rejected(unknown) -> + 3010; %% DIAMETER_UNKNOWN_PEER +rejected(N) + when is_integer(N) -> + N. %% open/5 -open(Pkt, SupportedApps, RCaps, {Type, IS}, #state{parent = Pid, - service = Svc} - = S) -> - #diameter_service{capabilities = #diameter_caps{origin_host = OH, - inband_security_id = LS} - = LCaps} - = Svc, - #diameter_caps{origin_host = DH} - = RCaps, +open(Pkt, SupportedApps, Caps, {Type, IS}, #state{parent = Pid} = S) -> + #diameter_caps{origin_host = {_,_} = H, + inband_security_id = {LS,_}} + = Caps, - tls_ack(lists:member(?TLS, LS), Type, IS, S), - Pid ! {open, self(), {OH,DH}, {capz(LCaps, RCaps), SupportedApps, Pkt}}, + tls_ack(lists:member(?TLS, LS), Caps, Type, IS, S), + Pid ! {open, self(), H, {Caps, SupportedApps, Pkt}}, S#state{state = 'Open'}. %% We've advertised TLS support: tell the transport the result %% and expect a reply when the handshake is complete. -tls_ack(true, Type, IS, #state{transport = TPid} = S) -> +tls_ack(true, Caps, Type, IS, #state{transport = TPid} = S) -> Ref = make_ref(), - MRef = erlang:monitor(process, TPid), TPid ! {diameter, {tls, Ref, Type, IS == ?TLS}}, receive {diameter, {tls, Ref}} -> - erlang:demonitor(MRef, [flush]); - {'DOWN', MRef, process, _, _} = T -> - close({tls_ack, T}, S) + ok; + {'DOWN', _, process, TPid, Reason} -> + close({tls_ack, Reason, Caps}, S) end; %% Or not. Don't send anything to the transport so that transports %% not supporting TLS work as before without modification. -tls_ack(false, _, _, _) -> +tls_ack(false, _, _, _, _) -> ok. capz(#diameter_caps{} = L, #diameter_caps{} = R) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 421e36ccf5..7adcf1c265 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -983,7 +983,8 @@ peer_cb(MFA, Alias) -> connection_down(Pid, #state{peerT = PeerT, connT = ConnT} = S) -> - #peer{conn = TPid} + #peer{op_state = ?STATE_UP, %% assert + conn = TPid} = P = fetch(PeerT, Pid), @@ -993,6 +994,9 @@ connection_down(Pid, #state{peerT = PeerT, %% connection_down/3 +connection_down(#peer{op_state = ?STATE_DOWN}, _, S) -> + S; + connection_down(#peer{conn = TPid, op_state = ?STATE_UP} = P, @@ -1034,13 +1038,23 @@ down_conn(Id, Alias, TC, {SvcName, Apps}) -> %% Peer process has died. -peer_down(Pid, _Reason, #state{peerT = PeerT} = S) -> +peer_down(Pid, Reason, #state{peerT = PeerT} = S) -> P = fetch(PeerT, Pid), ets:delete_object(PeerT, P), + closed(Reason, P, S), restart(P,S), peer_down(P,S). -%% peer_down/2 +%% Send an event at connection establishment failure. +closed({shutdown, {close, _TPid, Reason}}, + #peer{op_state = ?STATE_DOWN, + ref = Ref, + type = Type, + options = Opts}, + #state{service_name = SvcName}) -> + send_event(SvcName, {closed, Ref, Reason, {type(Type), Opts}}); +closed(_, _, _) -> + ok. %% The peer has never come up ... peer_down(#peer{conn = B}, S) @@ -1048,27 +1062,9 @@ peer_down(#peer{conn = B}, S) S; %% ... or it has. -peer_down(#peer{ref = Ref, - conn = TPid, - type = Type, - options = Opts} - = P, - #state{service_name = SvcName, - connT = ConnT} - = S) -> - #conn{caps = Caps} - = C - = fetch(ConnT, TPid), +peer_down(#peer{conn = TPid} = P, #state{connT = ConnT} = S) -> + #conn{} = C = fetch(ConnT, TPid), ets:delete_object(ConnT, C), - try - pd(P,C,S) - after - send_event(SvcName, {closed, Ref, {TPid, Caps}, {type(Type), Opts}}) - end. - -pd(#peer{op_state = ?STATE_DOWN}, _, S) -> - S; -pd(#peer{op_state = ?STATE_UP} = P, C, S) -> connection_down(P,C,S). %% restart/2 @@ -1259,11 +1255,11 @@ send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) -> #diameter_app{module = ModX} = App, - Pkt = make_packet(Msg), + Pkt = make_request_packet(Msg), case cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]) of {send, P} -> - send_request(make_packet(P, Pkt), + send_request(make_request_packet(P, Pkt), TPid, Caps, App, @@ -1278,70 +1274,73 @@ send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) -> ?ERROR({invalid_return, prepare_request, App, T}) end. -%% make_packet/1 +%% make_request_packet/1 %% %% Turn an outgoing request as passed to call/4 into a diameter_packet %% record in preparation for a prepare_request callback. -make_packet(Bin) +make_request_packet(Bin) when is_binary(Bin) -> #diameter_packet{header = diameter_codec:decode_header(Bin), bin = Bin}; -make_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]} = Pkt) -> - Pkt#diameter_packet{msg = [make_header(Hdr) | Avps]}; +make_request_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]} + = Pkt) -> + Pkt#diameter_packet{msg = [make_request_header(Hdr) | Avps]}; -make_packet(#diameter_packet{header = Hdr} = Pkt) -> - Pkt#diameter_packet{header = make_header(Hdr)}; +make_request_packet(#diameter_packet{header = Hdr} = Pkt) -> + Pkt#diameter_packet{header = make_request_header(Hdr)}; -make_packet(Msg) -> - make_packet(#diameter_packet{msg = Msg}). +make_request_packet(Msg) -> + make_request_packet(#diameter_packet{msg = Msg}). -%% make_header/1 +%% make_request_header/1 -make_header(undefined) -> +make_request_header(undefined) -> Seq = diameter_session:sequence(), - make_header(#diameter_header{end_to_end_id = Seq, - hop_by_hop_id = Seq}); + make_request_header(#diameter_header{end_to_end_id = Seq, + hop_by_hop_id = Seq}); -make_header(#diameter_header{version = undefined} = Hdr) -> - make_header(Hdr#diameter_header{version = ?DIAMETER_VERSION}); +make_request_header(#diameter_header{version = undefined} = Hdr) -> + make_request_header(Hdr#diameter_header{version = ?DIAMETER_VERSION}); -make_header(#diameter_header{end_to_end_id = undefined} = H) -> +make_request_header(#diameter_header{end_to_end_id = undefined} = H) -> Seq = diameter_session:sequence(), - make_header(H#diameter_header{end_to_end_id = Seq}); + make_request_header(H#diameter_header{end_to_end_id = Seq}); -make_header(#diameter_header{hop_by_hop_id = undefined} = H) -> +make_request_header(#diameter_header{hop_by_hop_id = undefined} = H) -> Seq = diameter_session:sequence(), - make_header(H#diameter_header{hop_by_hop_id = Seq}); + make_request_header(H#diameter_header{hop_by_hop_id = Seq}); -make_header(#diameter_header{} = Hdr) -> +make_request_header(#diameter_header{} = Hdr) -> Hdr; -make_header(T) -> +make_request_header(T) -> ?ERROR({invalid_header, T}). -%% make_packet/2 +%% make_request_packet/2 %% %% Reconstruct a diameter_packet from the return value of %% prepare_request or prepare_retransmit callback. -make_packet(Bin, _) +make_request_packet(Bin, _) when is_binary(Bin) -> - make_packet(Bin); + make_request_packet(Bin); -make_packet(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, _) -> +make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]} + = Pkt, + _) -> Pkt; %% Returning a diameter_packet with no header from a prepare_request %% or prepare_retransmit callback retains the header passed into it. %% This is primarily so that the end to end and hop by hop identifiers %% are retained. -make_packet(#diameter_packet{header = Hdr} = Pkt, +make_request_packet(#diameter_packet{header = Hdr} = Pkt, #diameter_packet{header = Hdr0}) -> Pkt#diameter_packet{header = fold_record(Hdr0, Hdr)}; -make_packet(Msg, Pkt) -> +make_request_packet(Msg, Pkt) -> Pkt#diameter_packet{msg = Msg}. %% fold_record/2 @@ -1533,7 +1532,7 @@ retransmit({TPid, Caps, #diameter_app{alias = Alias} = App}, case cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]) of {send, P} -> - retransmit(make_packet(P, Pkt), TPid, Caps, Req, Timeout); + retransmit(make_request_packet(P, Pkt), TPid, Caps, Req, Timeout); {discard, Reason} -> ?THROW(Reason); discard -> @@ -1946,7 +1945,7 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = Es, = ReqPkt) when [] == Es; is_record(hd(Msg), diameter_header) -> - Pkt = diameter_codec:encode(Dict, make_reply_packet(Msg, ReqPkt)), + Pkt = diameter_codec:encode(Dict, make_answer_packet(Msg, ReqPkt)), incr(send, Pkt, Dict, TPid), %% count result codes in sent answers send(TPid, Pkt#diameter_packet{transport_data = TD}); @@ -1957,18 +1956,19 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) -> TPid, Pkt#diameter_packet{errors = []}). -%% make_reply_packet/2 +%% make_answer_packet/2 %% Binaries and header/avp lists are sent as-is. -make_reply_packet(Bin, _) +make_answer_packet(Bin, _) when is_binary(Bin) -> #diameter_packet{bin = Bin}; -make_reply_packet([#diameter_header{} | _] = Msg, _) -> +make_answer_packet([#diameter_header{} | _] = Msg, _) -> #diameter_packet{msg = Msg}; %% Otherwise a reply message clears the R and T flags and retains the -%% P flag. The E flag will be set at encode. -make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) -> +%% P flag. The E flag will be set at encode. 6.2 of 3588 requires the +%% same P flag on an answer as on the request. +make_answer_packet(Msg, #diameter_packet{header = ReqHdr}) -> Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION, is_request = false, is_error = undefined, diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index b7c1491f4b..6dc53d9f31 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -179,11 +179,11 @@ transition({close, TPid, _Reason}, #watchdog{transport = TPid}) -> %% state okay as the result of the Peer State Machine reaching the %% Open state. %% -%% If we're an acceptor then we may be resuming a connection that went -%% down in another acceptor process, in which case this is the -%% transition below, from down into reopen. That is, it's not until -%% we know the identity of the peer (ie. now) that we know that we're -%% in state down rather than initial. +%% If we're accepting then we may be resuming a connection that went +%% down in another watchdog process, in which case this is the +%% transition below, from down to reopen. That is, it's not until we +%% know the identity of the peer (ie. now) that we know that we're in +%% state down rather than initial. transition({open, TPid, Hosts, T} = Open, #watchdog{transport = TPid, diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 69bcabbfbb..97d9069f4a 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -58,16 +58,18 @@ SUITES = $(SUITE_MODULES:diameter_%_SUITE=%) # target like 'all' below. Target release_tests only installs source. ERL_COMPILE_FLAGS += +warn_export_vars \ +warn_unused_vars \ - -DDIAMETER_CT=true \ + -I ../include \ -I ../src/gen # ---------------------------------------------------- # Targets # ---------------------------------------------------- -all: $(SUITES) +all: opt -beam tests debug opt: $(TARGET_FILES) +run: $(SUITES) + +debug opt: $(TARGET_FILES) clean: rm -f $(TARGET_FILES) @@ -94,22 +96,22 @@ help: @echo "Useful targets:" @echo @echo " all:" + @echo " Compile all test suites." + @echo + @echo " run:" @echo " Compile and run all test suites." @echo @echo " $(SUITES):" @echo " Compile and run a specific test suite." @echo - @echo " beam:" - @echo " Compile all test-code." - @echo @echo " clean | realclean:" @echo " Remove generated files." @echo @echo " info:" - @echo " Echo some interesting variables." + @echo " Echo some relevant variables." @echo ======================================== -.PHONY: all beam clean debug docs help info opt realclean tests +.PHONY: all run clean debug docs help info opt realclean # ---------------------------------------------------- # Special Targets @@ -118,12 +120,12 @@ help: # Exit with a non-zero status if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). The absolute -pa is # because ct will change directories. -$(SUITES): log tests +$(SUITES): log opt $(ERL) -noshell \ - -pa $(realpath ../ebin) \ - -sname diameter_test_$@ \ - -s diameter_ct run diameter_$@_SUITE \ - -s init stop \ + -pa $(realpath ../ebin) \ + -sname diameter_test_$@ \ + -s diameter_ct run diameter_$@_SUITE \ + -s init stop \ | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}' # Shorter in sed but requires a GNU extension (ie. Q). @@ -136,6 +138,9 @@ log: # Release Targets # ---------------------------------------------------- +/%: % force + sed -f release.sed $< > $(RELSYSDIR)$@ + ifeq ($(ERL_TOP),) include $(DIAMETER_TOP)/make/release_targets.mk else @@ -151,10 +156,16 @@ release_tests_spec: $(INSTALL_DATA) $(TEST_SPEC_FILE) \ $(COVER_SPEC_FILE) \ $(HRL_FILES) \ - $(ERL_FILES) \ $(RELSYSDIR) + $(MAKE) $(ERL_FILES:%=/%) + +force: .PHONY: release_spec release_docs_spec release_test_specs +.PHONY: force + +# Can't just make $(ERL_FILES:%=/%) phony since then implicit rule +# searching is skipped. # ---------------------------------------------------- @@ -163,7 +174,7 @@ depend: depend.mk # Generate dependencies makefile. depend.mk: depend.sed $(MODULES:%=%.erl) Makefile (for f in $(MODULES); do \ - sed -f $< $$f.erl | sed "s@/@/$$f@"; \ + (echo $$f; cat $$f.erl) | sed -f $<; \ done) \ > $@ diff --git a/lib/diameter/test/depend.sed b/lib/diameter/test/depend.sed index a399eb45f0..95dca44984 100644 --- a/lib/diameter/test/depend.sed +++ b/lib/diameter/test/depend.sed @@ -18,14 +18,24 @@ # # -# Extract local include dependencies from .erl files. The output is massaged -# further in Makefile. +# Extract local include dependencies from an .erl file. The first +# input line is the module name. # -/^-include/!d +# Store the module name in the hold space. +1{ + h + d +} + +# Throw away everything but local includes. /^-include_lib/d +/^-include/!d /diameter_gen/d +/diameter\./d +# Output a dependency of the beam on the included file. s@^-include("@@ s@".*@@ -s@^@$(EBIN)/.$(EMULATOR): @ +G +s@^\(.*\)\n\(.*\)@$(EBIN)/\2.$(EMULATOR): \1@ diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index d5ecdea291..7f53a4ddd4 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -134,13 +134,16 @@ release(Config) -> Rel = {release, {"diameter test release", fetch(vsn, App)}, {erts, erlang:system_info(version)}, - [{A, appvsn(A)} || A <- fetch(applications, App)]}, + [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]}, Dir = fetch(priv_dir, Config), ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel), {ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]}, {outdir, Dir}, silent]). +%% sasl need to be included to avoid a missing_sasl warning, error +%% in the case of relup/1. + appvsn(Name) -> [{application, Name, App}] = diameter_util:consult(Name, app), fetch(vsn, App). @@ -208,7 +211,7 @@ relup(Config) -> App = fetch(app, Config), Rel = [{erts, erlang:system_info(version)} - | [{A, appvsn(A)} || A <- fetch(applications, App)]], + | [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]], Dir = fetch(priv_dir, Config), @@ -216,12 +219,15 @@ relup(Config) -> UpFrom = acc_rel(Dir, Rel, Up), DownTo = acc_rel(Dir, Rel, Down), - {[Name], [Name], UpFrom, DownTo} %% no intersections + {[Name], [Name], [], []} %% no current in up/down and go both ways = {[Name] -- UpFrom, [Name] -- DownTo, UpFrom -- DownTo, DownTo -- UpFrom}, + [[], []] = [S -- sets:to_list(sets:from_list(S)) + || S <- [UpFrom, DownTo]], + {ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]}, {outdir, Dir}, silent]). diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl new file mode 100644 index 0000000000..e6b1558bf6 --- /dev/null +++ b/lib/diameter/test/diameter_capx_SUITE.erl @@ -0,0 +1,432 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Tests of capabilities exchange between Diameter nodes. In +%% particular, of error and event handling. +%% + +-module(diameter_capx_SUITE). + +-export([suite/0, + all/0, + groups/0, + init_per_group/2, + end_per_group/2, + init_per_testcase/2, + end_per_testcase/2]). + +%% testcases +-export([start/1, + start_services/1, + add_listeners/1, + s_no_common_application/1, + c_no_common_application/1, + s_no_common_security/1, + c_no_common_security/1, + s_unknown_peer/1, + c_unknown_peer/1, + s_unable/1, + c_unable/1, + s_client_reject/1, + c_client_reject/1, + remove_listeners/1, + stop_services/1, + stop/1]). + +%% diameter callbacks +-export([peer_up/4, + peer_down/4]). + +-include("diameter.hrl"). +-include("diameter_gen_base_rfc3588.hrl"). + +%% =========================================================================== + +-define(util, diameter_util). + +-define(CLIENT, client). +-define(SERVER, server). + +-define(ADDR, {127,0,0,1}). + +-define(REALM, "erlang.org"). +-define(HOST(Name), Name ++ "." ++ ?REALM). + +%% Config for diameter:start_service/2. +-define(SERVICE(Name), + [{'Origin-Realm', ?REALM}, + {'Host-IP-Address', [?ADDR]}, + {'Vendor-Id', 12345}, + {'Product-Name', "OTP/diameter"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]} + | [{application, [{alias, A}, + {dictionary, D}, + {module, [?MODULE, A]}]} + || {A,D} <- [{common, ?DIAMETER_DICT_COMMON}, + {accounting, ?DIAMETER_DICT_ACCOUNTING}]]]). + +-define(A, list_to_atom). +-define(L, atom_to_list). + +-define(event, #diameter_event). +-define(caps, #diameter_caps). +-define(packet, #diameter_packet). + +-define(cea, #diameter_base_CEA). +-define(answer_message, #'diameter_base_answer-message'). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [start, start_services, add_listeners + | [{group, N} || {N, _, _} <- groups()]] + ++ [remove_listeners, stop_services, stop]. + +groups() -> + Ts = testcases(), + [{grp(P), P, Ts} || P <- [[], [parallel]]]. + +grp([]) -> + sequential; +grp([parallel = P]) -> + P. + +init_per_group(_Name, Config) -> + Config. + +end_per_group(_, _) -> + ok. + +%% Generate a unique hostname for each testcase so that watchdogs +%% don't prevent a connection from being brought up immediately. +init_per_testcase(Name, Config) -> + Uniq = ["." ++ integer_to_list(N) || N <- tuple_to_list(now())], + [{host, lists:flatten([?L(Name) | Uniq])} | Config]. + +end_per_testcase(N, _) + when N == start; + N == start_services; + N == add_listeners; + N == remove_listeners; + N == stop_services; + N == stop -> + ok; +end_per_testcase(Name, Config) -> + CRef = ?util:read_priv(Config, Name), + ok = diameter:remove_transport(?CLIENT, CRef). + +%% Testcases all come in two flavours, client and server. +testcases() -> + lists:flatmap(fun tc/1, tc()). + +tc(Name) -> + [?A([C,$_|?L(Name)]) || C <- "cs"]. + +tc() -> + [no_common_application, + no_common_security, + unknown_peer, + unable, + client_reject]. + +%% =========================================================================== +%% start/stop testcases + +start(_Config) -> + ok = diameter:start(). + +start_services(_Config) -> + ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)), + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)). + +%% One server that responds only to base accounting, one that responds +%% to both this and the common application. Share a common service just +%% to simplify config, and because we can. +add_listeners(Config) -> + Acct = listen(?SERVER, + [{capabilities, [{'Origin-Host', ?HOST("acct-srv")}, + {'Auth-Application-Id', []}]}, + {applications, [accounting]}, + {capabilities_cb, [fun server_capx/3, acct]}]), + Base = listen(?SERVER, + [{capabilities, [{'Origin-Host', ?HOST("base-srv")}]}, + {capabilities_cb, [fun server_capx/3, base]}]), + ?util:write_priv(Config, ?MODULE, {Base, Acct}). %% lref/2 reads + +remove_listeners(_Config) -> + ok = diameter:remove_transport(?SERVER, true). + +stop_services(_Config) -> + ok = diameter:stop_service(?CLIENT), + ok = diameter:stop_service(?SERVER). + +stop(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== +%% All the testcases come in pairs, one for receiving an event on the +%% client side, one on the server side. Note that testcases will +%% receive events resulting from other testcases when running in +%% parallel since the events are per service. The unique client +%% Origin-Host for each testcase plus transport references are used to +%% ensure that only the relevant event is extracted from the mailbox. +%% Don't bother extracting events that aren't relevant. + +%% ==================== +%% Ask the accounting server to speak the common application and expect +%% DIAMETER_NO_COMMON_APPLICATION = 5010. + +s_no_common_application(Config) -> + server_closed(Config, fun no_common_application/1, 5010). + +c_no_common_application(Config) -> + client_closed(Config, "acct-srv", fun no_common_application/1, 5010). + +no_common_application(Config) -> + connect(Config, acct, [{capabilities, [{'Acct-Application-Id', []}]}, + {applications, [common]}]). + +%% ==================== +%% Ask the base server to speak accounting with an unknown security +%% method and expect DIAMETER_NO_COMMON_SECURITY = 5017. + +s_no_common_security(Config) -> + server_closed(Config, fun no_common_security/1, 5017). + +c_no_common_security(Config) -> + client_closed(Config, "base-srv", fun no_common_security/1, 5017). + +no_common_security(Config) -> + connect(Config, base, [{capabilities, [{'Acct-Application-Id', []}, + {'Inband-Security-Id', [17, 18]}]}, + {applications, [common]}]). + +%% ==================== +%% Have the base server reject a decent CER with the protocol error +%% DIAMETER_UNKNOWN_PEER = 3010. + +s_unknown_peer(Config) -> + server_reject(Config, fun base/1, 3010). + +c_unknown_peer(Config) -> + true = diameter:subscribe(?CLIENT), + OH = ?HOST("base-srv"), + + {CRef, _} = base(Config), + + {'CEA', ?caps{}, + ?packet{msg = ?answer_message{'Origin-Host' = OH, + 'Result-Code' = 3010}}} + = client_recv(CRef). + +base(Config) -> + connect(Config, base, []). + +%% ==================== +%% Have the base server reject a decent CER with the non-protocol +%% error DIAMETER_UNABLE_TO_COMPLY = 5012. + +s_unable(Config) -> + server_reject(Config, fun base/1, 5012). + +c_unable(Config) -> + client_closed(Config, "base-srv", fun base/1, 5012). + +%% ==================== +%% Have the client reject a decent CEA. + +s_client_reject(Config) -> + true = diameter:subscribe(?SERVER), + OH = host(Config), + + {_, LRef} = client_reject(Config), + + receive + ?event{service = ?SERVER, + info = {up, LRef, + {_, ?caps{origin_host = {_, OH}}}, + {listen, _}, + ?packet{}}} + = Info -> + Info + after 2000 -> + fail({LRef, OH}) + end. + +c_client_reject(Config) -> + true = diameter:subscribe(?CLIENT), + OH = ?HOST("acct-srv"), + + {CRef, _} = client_reject(Config), + + {'CEA', {capabilities_cb, _, discard}, + ?caps{origin_host = {_, OH}}, + ?packet{msg = ?cea{'Result-Code' = 2001}}} + = client_recv(CRef). + +client_reject(Config) -> + connect(Config, acct, [{capabilities_cb, fun client_capx/2}]). + +%% =========================================================================== + +%% server_closed/3 + +server_closed(Config, F, RC) -> + true = diameter:subscribe(?SERVER), + OH = host(Config), + + {_, LRef} = F(Config), + + receive + ?event{service = ?SERVER, + info = {closed, LRef, + {'CER', RC, + ?caps{origin_host = {_, OH}}, + ?packet{}} + = Reason, + {listen, _}}} -> + Reason + after 2000 -> + fail({LRef, OH}) + end. + +%% server_reject/3 + +server_reject(Config, F, RC) -> + true = diameter:subscribe(?SERVER), + OH = host(Config), + + {_, LRef} = F(Config), + + receive + ?event{service = ?SERVER, + info = {closed, LRef, + {'CER', {capabilities_cb, _, RC}, + ?caps{origin_host = {_, OH}}, + ?packet{}} + = Reason, + {listen, _}}} -> + Reason + after 2000 -> + fail({LRef, OH}) + end. + +%% cliient_closed/4 + +client_closed(Config, Host, F, RC) -> + true = diameter:subscribe(?CLIENT), + OH = ?HOST(Host), + + {CRef, _} = F(Config), + + {'CEA', RC, ?caps{origin_host = {_, OH}}, ?packet{}} + = client_recv(CRef). + +%% client_recv/1 + +client_recv(CRef) -> + receive + ?event{service = ?CLIENT, + info = {closed, CRef, Reason, {connect, _}}} -> + Reason + after 2000 -> + fail(CRef) + end. + +%% server_capx/3 + +server_capx(_, ?caps{origin_host = {_, [_,$_|"unknown_peer." ++ _]}}, _) -> + unknown; + +server_capx(_, ?caps{origin_host = {_, [_,$_|"unable." ++ _]}}, _) -> + 5012; %% DIAMETER_UNABLE_TO_COMPLY + +server_capx(_, ?caps{origin_host = {OH,DH}}, _) -> + io:format("connection: ~p -> ~p~n", [DH,OH]), + ok. + +%% client_capx/2 + +client_capx(_, ?caps{origin_host = {[_,$_|"client_reject." ++ _], _}}) -> + discard. + +%% =========================================================================== + +fail(T) -> + erlang:error({T, process_info(self(), messages)}). + +host(Config) -> + {_, H} = lists:keyfind(host, 1, Config), + ?HOST(H). + +listen(Name, Opts) -> + ?util:listen(Name, tcp, Opts). + +connect(Config, T, Opts) -> + {_, H} = lists:keyfind(host, 1, Config), + LRef = lref(Config, T), + CRef = connect(LRef, [{capabilities, [{'Origin-Host', ?HOST(H)}]} + | Opts]), + Name = lists:takewhile(fun(C) -> C /= $. end, H), + ?util:write_priv(Config, Name, CRef), %% end_per_testcase reads + {CRef, LRef}. + +connect(LRef, Opts) -> + [PortNr] = ?util:lport(tcp, LRef, 20), + {ok, CRef} = diameter:add_transport(?CLIENT, + {connect, opts(PortNr, Opts)}), + CRef. + +opts(PortNr, Opts) -> + [{transport_module, diameter_tcp}, + {transport_config, [{raddr, ?ADDR}, + {rport, PortNr}, + {ip, ?ADDR}, + {port, 0}]} + | Opts]. + +lref(Config, T) -> + case ?util:read_priv(Config, ?MODULE) of + {LRef, _} when T == base -> + LRef; + {_, LRef} when T == acct -> + LRef + end. + +%% =========================================================================== +%% diameter callbacks + +peer_up(?SERVER, + {_, ?caps{origin_host = {"acct-srv." ++ _, + [_,$_|"client_reject." ++ _]}}}, + State, + _) -> + State. + +peer_down(?SERVER, + {_, ?caps{origin_host = {"acct-srv." ++ _, + [_,$_|"client_reject." ++ _]}}}, + State, + _) -> + State. diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl index aab7ab35cc..8046ca4c04 100644 --- a/lib/diameter/test/diameter_codec_test.erl +++ b/lib/diameter/test/diameter_codec_test.erl @@ -25,7 +25,7 @@ %% Test encode/decode of dictionary-related modules. %% --include_lib("diameter/include/diameter.hrl"). +-include("diameter.hrl"). -define(BASE, diameter_gen_base_rfc3588). -define(BOOL, [true, false]). diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl index c25e9682f0..f4d62f94c6 100644 --- a/lib/diameter/test/diameter_failover_SUITE.erl +++ b/lib/diameter/test/diameter_failover_SUITE.erl @@ -57,13 +57,8 @@ handle_error/4, handle_request/3]). --ifdef(DIAMETER_CT). +-include("diameter.hrl"). -include("diameter_gen_base_rfc3588.hrl"). --else. --include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). --endif. - --include_lib("diameter/include/diameter.hrl"). -include("diameter_ct.hrl"). %% =========================================================================== diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index 03f1115496..40cbdf805a 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -64,13 +64,8 @@ handle_error/4, handle_request/3]). --ifdef(DIAMETER_CT). +-include("diameter.hrl"). -include("diameter_gen_base_rfc3588.hrl"). --else. --include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). --endif. - --include_lib("diameter/include/diameter.hrl"). -include("diameter_ct.hrl"). %% =========================================================================== diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 99f92ca0e0..127e3435dc 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -67,13 +67,8 @@ handle_error/4, handle_request/3]). --ifdef(DIAMETER_CT). +-include("diameter.hrl"). -include("diameter_gen_base_rfc3588.hrl"). --else. --include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). --endif. - --include_lib("diameter/include/diameter.hrl"). -include("diameter_ct.hrl"). %% =========================================================================== diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 6704f24532..55c5fc7c54 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -87,13 +87,8 @@ handle_error/5, handle_request/3]). --ifdef(DIAMETER_CT). +-include("diameter.hrl"). -include("diameter_gen_base_rfc3588.hrl"). --else. --include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). --endif. - --include_lib("diameter/include/diameter.hrl"). -include("diameter_ct.hrl"). %% =========================================================================== @@ -251,7 +246,7 @@ start_services(_Config) -> ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)). add_transports(Config) -> - LRef = ?util:listen(?SERVER, tcp), + LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}]), CRef = ?util:connect(?CLIENT, tcp, LRef), ?util:write_priv(Config, "transport", {LRef, CRef}). @@ -266,6 +261,10 @@ stop_services(_Config) -> stop(_Config) -> ok = diameter:stop(). +capx(_, #diameter_caps{origin_host = {OH,DH}}) -> + io:format("connection: ~p -> ~p~n", [DH,OH]), + ok. + %% =========================================================================== %% Ensure that result codes have the expected values. diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index a9520ef5bd..c22adc3334 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -45,7 +45,7 @@ init/2]). -include_lib("kernel/include/inet_sctp.hrl"). --include_lib("diameter/include/diameter.hrl"). +-include("diameter.hrl"). -include("diameter_ct.hrl"). -define(util, diameter_util). diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 3fe8ea5363..6b1dc1f0c9 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -33,8 +33,8 @@ %% diameter-specific -export([lport/2, lport/3, - listen/2, - connect/3, + listen/2, listen/3, + connect/3, connect/4, disconnect/4]). %% common_test-specific @@ -254,22 +254,28 @@ lp(M, Ref, T) -> end. %% --------------------------------------------------------------------------- -%% listen/2 +%% listen/2-3 %% %% Add a listening transport on the loopback address and a free port. listen(SvcName, Prot) -> - add_transport(SvcName, {listen, opts(Prot, listen)}). + listen(SvcName, Prot, []). + +listen(SvcName, Prot, Opts) -> + add_transport(SvcName, {listen, opts(Prot, listen) ++ Opts}). %% --------------------------------------------------------------------------- -%% connect/3 +%% connect/2-3 %% %% Add a connecting transport on and connect to a listening transport %% with the specified reference. connect(Client, Prot, LRef) -> + connect(Client, Prot, LRef, []). + +connect(Client, Prot, LRef, Opts) -> [PortNr] = lport(Prot, LRef, 20), - Ref = add_transport(Client, {connect, opts(Prot, PortNr)}), + Ref = add_transport(Client, {connect, opts(Prot, PortNr) ++ Opts}), true = diameter:subscribe(Client), ok = receive {diameter_event, Client, {up, Ref, _, _, _}} -> ok diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index dec307529a..b40d7c104d 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -36,7 +36,7 @@ id/1, %% jitter callback run/1]). --include_lib("diameter/include/diameter.hrl"). +-include("diameter.hrl"). -include("diameter_ct.hrl"). %% =========================================================================== diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 75fdd0bd1d..f88258c232 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -33,6 +33,7 @@ MODULES = \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ diameter_transport_SUITE \ + diameter_capx_SUITE \ diameter_traffic_SUITE \ diameter_relay_SUITE \ diameter_tls_SUITE \ diff --git a/lib/diameter/test/release.sed b/lib/diameter/test/release.sed new file mode 100644 index 0000000000..2720b778f2 --- /dev/null +++ b/lib/diameter/test/release.sed @@ -0,0 +1,35 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# 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 online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +# This bit of gymnastics is to replace the include of diameter's +# public hrls by include_lib when releasing testsuites, so that they +# compile both in the development filesystem (where generated hrls +# aren't in diameter/include) and with common_test's autocompilation +# on an installed release. Solving the problem by installing generated +# hrls to ../include is anathema: that directory is for handwritten +# source.) +# + +/^-include("/!b +/"diameter_gen_/b s +/"diameter\./!b + +:s +s@("@_lib&diameter/include/@ diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index c783450c9f..b1d3ba2241 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 0.10 +DIAMETER_VSN = 0.11 PRE_VSN = APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)" diff --git a/lib/docbuilder/AUTHORS b/lib/docbuilder/AUTHORS deleted file mode 100644 index 4f2a8e9361..0000000000 --- a/lib/docbuilder/AUTHORS +++ /dev/null @@ -1,10 +0,0 @@ -Docbuilder is a rewrite of the Old docbuilder -and takes XML as input instead of SGML. -Docbuilder makes use of xmerl for parsing XML -and produces HTML. Everything is written in Erlang -and there are no dependencies to external tools. - -Original Authors: -Gunilla Arendt - -Contributors: diff --git a/lib/docbuilder/Makefile b/lib/docbuilder/Makefile deleted file mode 100644 index 21f42421d6..0000000000 --- a/lib/docbuilder/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# ``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 express 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, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# -# Macros -# - -SUB_DIRECTORIES = src dtd etc doc/src - -include vsn.mk -VSN = $(DOCB_VSN) - -SPECIAL_TARGETS = - -# -# Default Subdir Targets -# -include $(ERL_TOP)/make/otp_subdir.mk - - diff --git a/lib/docbuilder/doc/pdf/.gitignore b/lib/docbuilder/doc/pdf/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/docbuilder/doc/pdf/.gitignore +++ /dev/null diff --git a/lib/docbuilder/doc/src/book.xml b/lib/docbuilder/doc/src/book.xml deleted file mode 100644 index a13d56dd8a..0000000000 --- a/lib/docbuilder/doc/src/book.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE book SYSTEM "book.dtd"> - -<book xmlns:xi="http://www.w3.org/2001/XInclude"> - <header titlestyle="normal"> - <copyright> - <year>1997</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>DocBuilder</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <insidecover> - </insidecover> - <pagetext>Docbuilder</pagetext> - <preamble> - <contents level="2"></contents> - </preamble> - <parts lift="no"> - <xi:include href="part.xml"/> - </parts> - <applications> - <xi:include href="ref_man.xml"/> - </applications> - <releasenotes> - <xi:include href="notes.xml"/> - </releasenotes> - <listoffigures></listoffigures> - <listoftables></listoftables> - <listofterms></listofterms> - <index></index> -</book> - diff --git a/lib/docbuilder/doc/src/docb_gen.xml b/lib/docbuilder/doc/src/docb_gen.xml deleted file mode 100644 index d4ebfd0f84..0000000000 --- a/lib/docbuilder/doc/src/docb_gen.xml +++ /dev/null @@ -1,213 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>1999</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express 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 AB. - </legalnotice> - <title>docb_gen</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>docb_gen</module> - <modulesummary>Generate XML from EDoc comments in Erlang source code. - </modulesummary> - - <description> - <p><c>docb_gen</c> contains functions for generating XML - documentation source code according to the <c>erlref</c> or - <c>chapter</c> DTD from - <seealso marker="edoc:chapter">EDoc</seealso> comments in Erlang - source code or an <c>overview.edoc</c> file, using EDoc.</p> - </description> - - <funcs> - <func> - <name>module(File) -> ok | {error, Reason}</name> - <name>module(File, Options) -> ok | {error, Reason}</name> - <fsummary>Generate XML from EDoc comments in Erlang source code. - </fsummary> - <type> - <v>File = string()</v> - <v>Options = [Opt]</v> - <v>Opt = {def,Defs} | {includes,Dirs} | {preprocess,Bool} - | {sort_functions,Bool}</v> - <v>Defs = [{atom(),string()}]</v> - <v>Dirs = [string()]</v> - <v>Bool = bool()</v> - <v>Reason = badfile | {badopt,term()} | term()</v> - </type> - <desc> - <p>Generates XML documentation source code according to - the <c>erlref</c> DTD from EDoc comments <c>File</c>, using - the EDoc application.</p> - - <p><c>File</c> is an Erlang source file, given with or without - the <c>.erl</c> extension as <c>Name.erl</c> or <c>Name</c>. - The resulting XML file is created in the current working - directory and named <c>Name.xml</c>.</p> - - <p><c>Options</c> is a list of options, see below.</p> - - <p>Returns <c>ok</c> if successful, and an error tuple - otherwise.</p> - </desc> - </func> - - <func> - <name>users_guide(File) -> ok | {error, Reason}</name> - <name>users_guide(File, Options) -> ok | {error, Reason}</name> - <fsummary>Generate XML from EDoc comments in Erlang source code - </fsummary> - <type> - <v>File -- see module/1,2</v> - <v>Options -- see module/1,2</v> - <v>Reason -- see module/1,2</v> - </type> - <desc> - <p>Like <c>module/1,2</c> but generates XML source code - according to the <c>chapter</c> DTD from an - <c>overview.edoc</c> or similar file.</p> - - <p>The resulting file is named <c>chapter.xml</c>.</p> - </desc> - </func> - </funcs> - - <section> - <title>Options</title> - <taglist> - <tag><c>{def, [{Name,Text}]}</c></tag> - <item>Specifies EDoc macro definitions. See - <seealso marker="edoc:edoc">edoc:get_doc/2</seealso>.</item> - - <tag><c>{includes, [Dir]}</c></tag> - <item>Specifies directories where EDoc should search for include - files. See - <seealso marker="edoc:edoc">edoc:read_source/2</seealso>.</item> - - <tag><c>{preprocess, true|false}</c></tag> - <item>Specifies if EDoc should read the source file via the Erlang - preprocessor. Default is <c>false</c>. See - <seealso marker="edoc:edoc">edoc:read_source/2</seealso>.</item> - - <tag><c>{sort_functions, true|false}</c></tag> - <item>Specifies if the functions in the resulting XML file should - be sorted alphabetically. Default is <c>true</c>.</item> - </taglist> - </section> - - <section> - <title>Limitations</title> - <p>The mapping from the EDoc XHTML output to valid Erlang/OTP XML - is not complete. An attempt has been made to cover the most - commonly used XHTML constructs, but there will still be cases - where XML generation fails or where the resulting XML is - inadequate. This is especially true for <c>users_guide/1,2</c>. - </p> - - <p>Known limitations for some XHTML tags:</p> - <taglist> - <tag><c><![CDATA[<a>]]></c></tag> - <item> - <p>All attributes except the first <c>href</c> or <c>name</c> - attribute are ignored.</p> - <p>A <c>href</c> attribute means the <c><![CDATA[<a>]]></c> tag - will be transformed to a <c><![CDATA[<seealso>]]></c> or - <c><![CDATA[<url>]]></c> tag and an attempt is made to - resolve the reference if necessary.</p> - - <p>A <c>name</c> attribute means the <c><![CDATA[<a>]]></c> tag - will be transformed to a <c><![CDATA[<marker>]]></c> tag.</p> - </item> - - <tag><c><![CDATA[<b>, <em>, <pre>]]></c></tag> - <item>Cannot contain other tags in Erlang/OTP XML, content is - converted to plain text. - </item> - - <tag><c><![CDATA[<center>]]></c></tag> - <item>No corresponding Erlang/OTP XML tag, converted to plain - text. - </item> - - <tag><c><![CDATA[<font>]]></c></tag> - <item>No corresponding Erlang/OTP XML tag, converted to plain - text. - </item> - - <tag><c><![CDATA[<h1>, <h2>, ...]]></c></tag> - <item>There is no tag corresponding to a header in Erlang/OTP XML, - so these are converted to plain text instead, with - the exception of <c><![CDATA[<h3>]]></c> and - <c><![CDATA[<h4>]]></c> tags within <c>overview.edoc</c>, see - part about "<c>chapter</c> DTD" below. - </item> - - <tag><c><![CDATA[<sup>]]></c></tag> - <item>There is no tag corresponding to superscript in Erlang/OTP - XML, so this is converted to plain text within brackets "(..)". - </item> - - <tag>References</tag> - <item>The markers automatically inserted by EDoc at each heading - and function will override the markers automatically inserted - by DocBuilder, with the unfortunate result that the links in - the left-hand frame of the User's Guide will not work, and - also that cross referencing a function in a module the usual - Erlang/OTP way - "<c><![CDATA[<seealso marker="edoc:edoc#run/3...>]]></c>" does - not work. (But - "<c><![CDATA[<seealso marker="edoc:edoc#run-3...>]]></c>" does.) - </item> - </taglist> - - <p><em>erlref DTD</em></p> - <taglist> - <tag>Tables</tag> - <item>Tables are not allowed. The contents of a table is - converted to text instead, each row corresponding to one line - of text. - </item> - </taglist> - - <p><em>chapter DTD</em></p> - <taglist> - <tag>Sections</tag> - <item>Only two levels of sections. <c><![CDATA[<h3>]]></c> - (equivalent to EDoc headings "<c>== Heading ==</c>") is - interpreted as start of top-level section, or if there is no - <c><![CDATA[<h3>]]></c> tag, the entire document is made into - one top-level section. <c><![CDATA[<h4>]]></c> (equivalent to - EDoc sub-headings ("<c><![CDATA[=== Sub-heading ===]]></c>") is - interpreted as start of second-level section. - </item> - - <tag>Tables</tag> - <item>Tables without borders are converted to text in the same - manner as for the <c>erlref</c> DTD. - </item> - </taglist> - </section> - -</erlref> - diff --git a/lib/docbuilder/doc/src/docb_transform.xml b/lib/docbuilder/doc/src/docb_transform.xml deleted file mode 100644 index 06a04c8c02..0000000000 --- a/lib/docbuilder/doc/src/docb_transform.xml +++ /dev/null @@ -1,224 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2001</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express 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 AB. - </legalnotice> - - <title>docb_transform</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>docb_transform</module> - <modulesummary>Transform XML to HTML</modulesummary> - <description> - <p><c>docb_transform</c> contains functions for transforming XML - documentation source code to HTML.</p> - </description> - - <funcs> - <func> - <name>file(File) -> ok | {error, Reason}</name> - <name>file(File, Options) -> ok | {error, Reason}</name> - <fsummary>Transform XML to HTML</fsummary> - <type> - <v>File = string()</v> - <v>Options = [Opt]</v> - <v>Opt -- see below</v> - </type> - <desc> - <p>Transforms XML documentation source code to HTML.</p> - - <p><c>File</c> is a documentation source file, given with or - without the <c>.xml</c> extension as <c>Name.xml</c> or - <c>Name</c>.</p> - - <p>If <c>File</c> contains XML code according to a basic DTD - (<c>chapter</c>, <c>erlref</c>, ...), the resulting HTML - file is named <c>Name.html</c>.</p> - - <p>If <c>File</c> contains XML code according to a compound DTD - (<c>application</c> or <c>part</c>), several files are - created:</p> - <list> - <item>A cover page for the application with two frames, - <c>Name_frame.html</c>.</item> - <item>The contents of the left frame and a front page, - <c>Name.html</c> and <c>Name_first.html</c>.</item> - <item>A bibliography and a glossary, <c>Name_cite.html</c> - and <c>Name_term.html</c>.</item> - <item>In the case of an <c>application</c> DTD an index - is created, <c>Name.kwc</c> and <c>Name_index.html</c>. - </item> - <item>One HTML file for each file included from <c>File</c>. - </item> - <item>Also, if there exists a <c>fascicules.xml</c> file where - the value of the <c>entry</c> attribute for <c>File</c> is - <c>"yes"</c>, the cover page is copied to <c>index.html</c>. - </item> - </list> - </desc> - </func> - </funcs> - - <section> - <title>Options</title> - <taglist> - <tag><c>{html_mod, Module}, Module=atom()</c></tag> - <item> - <p>A callback module can be used for specifying HTML snippets - that should be included in the generated HTML files, see - below.</p> - </item> - - <tag><c>{outdir, Dir}, Dir=string()</c></tag> - <item> - <p>Destination for generated files. Default is current working - directory.</p> - </item> - - <tag><c>{number, Number}, Number=int()</c></tag> - <item> - <p>First chapter number when transforming a <c>chapter</c> - file. Default is 1.</p> - </item> - - <tag><c>{ptype, unix|windows}</c></tag> - <item> - <p>For <c>path</c> elements, the specified file path should be - presented.</p> - </item> - - <tag><c>silent</c></tag> - <item> - <p>Silent - no warnings, only error information is printed.</p> - </item> - - <tag><c>{top, Index}, Index=string()</c></tag> - <item> - <p>Specifies the value of "Top" in the left frame of a front - page, which normally should be some kind of top index file - for the documentation.</p> - </item> - - <tag><c>{vsn, Vsn}, Vsn=string()</c></tag> - <item> - <p>Application version number. Overrides a version number - defined in the XML document. Visible in the left frame and - on the front page.</p> - </item> - - <tag><c>{term_defs, File}, File=string()</c></tag> - <item> - <p>Use the global glossary definitions in <c>File</c>, which - should contain a list of tuples <c>{Id, Name, Definition, - Owner}</c>. See the section - <seealso marker="inline_tags#termTAG"><term>, - <termdef> - Glossary</seealso> in the User's Guide. - </p> - </item> - - <tag><c>{cite_defs, File}, File=string()</c></tag> - <item> - <p>Use the global bibliography definitions in <c>File</c>, which - should contain a list of tuples <c>{Id, Title, Info, - Owner}</c>. See the section - <seealso marker="inline_tags#citeTAG"><cite>, - <citedef> - Bibliography</seealso> in the User's - Guide.</p> - </item> - </taglist> - </section> - - <section> - <title>Callback Module</title> - - <p>A <c>html_mod</c> callback module can include the functions - specified below. Note that there is no check that the resulting - HTML code is valid. All functions are optional.</p> - </section> - - <funcs> - <func> - <name>Module:head() -> string()</name> - <fsummary>Snippet to be included in head of a document.</fsummary> - <desc> - <p>Defines a HTML snippet to be included in the head of - a document, after the <c><HEAD></c> start tag and - <c><TITLE></c> tag:</p> - <pre> -<HTML> -<HEAD> - <TITLE>...</TITLE> - - snippet is included here - - ... -</HEAD> -... -</HTML> - </pre> - </desc> - </func> - - <func> - <name>Module:top() -> string()</name> - <fsummary>Snippet to be included at the top of a document. - </fsummary> - <desc> - <p>Defines a HTML snippet to be included at the top of a - document, after the <c><BODY></c> start tag.</p> - </desc> - </func> - - <func> - <name>Module:bottom() -> string()</name> - <fsummary>Snippet to be included at the bottom of a document. - </fsummary> - <desc> - <p>Defines a HTML snippet to be included at the bottom of a - document, before the <c></BODY></c> end tag.</p> - </desc> - </func> - - <func> - <name>Module:seealso(SeeAlso) -> Href</name> - <fsummary></fsummary> - <type> - <v>SeeAlso = Href = string()</v> - </type> - <desc> - <p>When referring to another part of the document, or another - document, the XML tag <c><seealso></c> is used: - <c><![CDATA[<seealso marker="File#Marker">...text...</seealso>]]></c>. - By default, this is translated to - <c><![CDATA[<A HREF="File.html#Marker>...text...</A>]]></c>.</p> - - <p>This function makes it possible to specify an alternative - translation <c>Href</c> of the <c>marker</c> attribute value - <c>SeeAlso</c>. For example, in OTP this is used to resolve - cross references between applications.</p> - </desc> - </func> - </funcs> - -</erlref> - diff --git a/lib/docbuilder/doc/src/docbuilder_app.xml b/lib/docbuilder/doc/src/docbuilder_app.xml deleted file mode 100644 index 58b8daf598..0000000000 --- a/lib/docbuilder/doc/src/docbuilder_app.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE appref SYSTEM "appref.dtd"> - -<appref> - <header> - <copyright> - <year>2007</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express 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 AB. - </legalnotice> - - <title>docbuilder</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <app>docbuilder</app> - <appsummary>The DocBuilder Application</appsummary> - <description> - <p>DocBuilder provides functionality for generating HTML - documentation for Erlang modules and Erlang/OTP applications - from XML source code and/or EDoc comments in Erlang source code. - </p> - </description> - - <section> - <title>Limitations</title> - <p>DocBuilder is primarily intended for generating documentation - for Erlang/OTP itself. That is, no attempt has been made to create - a tool suitable for generating documentation in general.</p> - </section> - - <section> - <title>See Also</title> - <p>DocBuilder User's Guide, - <seealso marker="docb_gen">docb_gen(3)</seealso>, - <seealso marker="docb_transform">docb_transform(3)</seealso> - <seealso marker="docb_xml_check"></seealso></p> - </section> - -</appref> - diff --git a/lib/docbuilder/doc/src/make.dep b/lib/docbuilder/doc/src/make.dep deleted file mode 100644 index d9b075e114..0000000000 --- a/lib/docbuilder/doc/src/make.dep +++ /dev/null @@ -1,33 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: block_tags.tex book.tex character_entities.tex \ - docb_gen.tex docb_transform.tex docb_xml_check.tex \ - docbuilder_app.tex fasc_dtds.tex header_tags.tex \ - inline_tags.tex overview.tex part.tex ref_man.tex \ - refman_dtds.tex user_guide_dtds.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -block_tags.tex: gazonk - -book.tex: ref_man.xml - -inline_tags.tex: ../../../../system/doc/definitions/term.defs - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: man.ps - diff --git a/lib/docbuilder/doc/src/man.ps b/lib/docbuilder/doc/src/man.ps deleted file mode 100644 index b4d7ef7636..0000000000 --- a/lib/docbuilder/doc/src/man.ps +++ /dev/null @@ -1,750 +0,0 @@ -%!PS-Adobe-2.0 EPSF-2.0 -%%Title: /clearcase/otp/internal_tools/sgml/test/man.ps -%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley -%%BoundingBox: 243 308 369 484 -%%Pages: 1 -%%DocumentFonts: -%%EndComments -%%EndProlog - -%%Page: 1 1 - -% remember original state -/origstate save def - -% build a temporary dictionary -20 dict begin - -% define string to hold a scanline's worth of data -/pix 126 string def - -% define space for color conversions -/grays 126 string def % space for gray scale line -/npixls 0 def -/rgbindx 0 def - -% lower left corner -243 308 translate - -% size of image (on paper, in 1/72inch coords) -126.00000 175.96800 scale - -126 176 8 % dimensions of data -[126 0 0 -176 0 176] % mapping matrix -{currentfile pix readhexstring pop} -image - -110000110011111111111100111111110011110011111111111100111111112222222222 -33445544446655665555665566666655666666888888778899888899aabbaabbbbbbaabb -bbaaaaaaaabbbbbbaabbccddbbaaaaccccccddddccddddccbbccccccbbccccaabbaaaaaa -9999aaaa8899887777554455666655555544 -000000110011110000001100112222111111001111111100001111111111112222112233 -55334444446666775544555555775577777766888888889988889999aaccbbaabb99aaaa -bbbbaaaaaaaabbbbccccccccccccbbccccccccddccddddccbbaaccddccbbaaccbbbbaaaa -999999889977667755554455666655444444 -110011000011000000111111111100111100112211111111110011111111112222222233 -3344444455446677665555667777667788888888667788aa88999999aabbaabbaa889999 -aabbbbbbaaaaaabbddccccccbbccccccbbaaccccccccccccbbccccccccbbbbbbbbaaaa99 -9999aa888877666655555555555544333344 -110000110011110000001111111111000011001122110011111111002211222211224433 -3333444444556677666655667777667777888877666688998899aa99aabbaaaaaaaabbaa -99aabbaabbbbbbbbbbccbbddaabbccbbaa99ccddccccccbbccccccddccbbbbaaccaa9988 -889988887766665566665544443344554444 -000000000000110011000000110000110000001111000000111100221111111133222222 -33444433444455667777555555776666778888667777778888aa998888bbaa99aaaaaabb -bbbbbbaabbccbbbbbbccbbbbbbccccaabbbbbbccccccbbbbbbbbccbbbbbbbbbbbbaa7788 -aa9988889966666655666655553355556644 -110011111111111100111100110011000000001100002211111122221122111122222222 -33443333334455776666776666667766778855668866777788448899889988889999bbaa -aaaabbaaaabbbbaabbbbbbbbbbbbaa99bbaabbccddccccccbbccbbbbaabbbbaaaa777788 -aa9999aa9988776677777755555544556655 -110000001111111122111111000000001111110011111111110022111111111133222233 -223322445555445544667777667777667777887788887799883377999999998899aaaaaa -99aabbbbccbbbbbbbbbbaaaaaabb99aaaabbbbbbccccccbbccccbbbbaabbaaccaa886688 -9999aaaa9988888866667744555544445544 -110000111122111111221100111111110011111111111100111111222222221122333333 -22222244556655445555667788778888aaaa88aa889999aabbaaaa998888998899aa99aa -bbaabbccbbbbaaaabbbbbbbbbbbbaabbaaaaccccccbbccddccbbaabbaabbaabb99888888 -99aa99aa9988888866446655554444444444 -110000001111111111110011110000111100221111001111000011222222222222333344 -223322444466664455667766777788777755556666333344557788aa9999888888aa88aa -aabbbbaabbaaccbbaaaaaaccbbccaa99bbccccccccbbccccccbbbbbbbbaabbaaaa99aa88 -999988999988887766664455445555555544 -110011111100001111111111110000000011111111110011111122111111112233222222 -443333555544444455777788775522000000000000000000000000447799aaaa99888899 -aaaabbaaaaccbbaaaabbbbbbbbaa7788bbddccccbbbbbbbbccbbbbaabbaaaaaaaaaa9999 -aa999988aa99887766666655444455445544 -000000110011110000110000110011001100001111110000111122112211112211222222 -5544444455443333446677772200000000000000000000000000000000337799999999aa -9999aabbbbbbaaaa88aaaabbbb889988ccccccbbccbbbbaaaa9999bb8855889999999988 -998888998888886655667755554455554433 -110011001111001100001100111111000000001100111100111111222211113333222211 -44555544444433445555550000000000000000000000000011000000000000003377aa99 -888899aa99aa9999aaaabbaabb99aabbaabbbbccaabbaaaabb88aaaa995588aaaaaa8888 -8888aa998888887755777766554444332222 -111111110011111111001111001111110000000011000011001111111122332222223322 -334466554444444455441100000000000000000000000000000000001155220000113366 -998888aa99998899bbbbaabbbbaaaaaabbbbbbbbbbaabbaaaa99aaaa8888aa9999889988 -7799aa888888665566666655554433334422 -221111110011000011111111110000000000110011110000111111001111333311223333 -443344443344554488440011553300000000000000000000000000227788883300000011 -4444559999887799aaaaaaccbbaaaa9988ccccbbaabbbbaaaa99aa9988aa999988888888 -776688888877667766554455444444444433 -221111110011111100110011000011000000000000110000110011001111112222221122 -2222333333111111448899ccffddbb77442222221111000000000044bbddccaa33000000 -00000000558888998899bbaabbaabbaa99bbaabbaaaabbaa99aa99999988778888777777 -663355778877776666665544444433333322 -221100222211001111112200111111000011000000000011001100111111112211112211 -332244220011000055ddffeeeeeeeeeeddddddeeddcc88330000000044ddddcc55000000 -000000000077aaaa999999aaaabbbbbbaa99aabbbbaaaabbaaaaaa999999888888557755 -664466666677666655667755443333223322 -221111222211221111111100000011110000110000001100111111110011111122112222 -3322000000000044ddffffeeffeeeeeeeeeeeeeeffeeffdd885511000033aaddaa330011 -2211000000339988889999aaaaaabbaabbbbbbbbbbaaaaaabb99aa8899aa999988665577 -665577777766555544443366443344333322 -221111111122221111001111111100000000000000001111111111111111111111223344 -22000000000077ddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffeebb440000005588661100 -11000000001188888888aa9999aabbbbbbaaaabbaabbbbbbaa8899888899888888776666 -556666776666443366555555445533333333 -112211111122221111221100111100110000000000001111001100000000111122112211 -000000000088eeeeeeeeeeeeffeeeeffffeeeeeeffeeeeeeeeeeffee8811000000118866 -0000000000118899888899aaaabbbbbbbbbbbb99aabbaaaaaa9988888877888877555566 -555555666655446655556655444444443344 -221111111100111111110011111111110011001100110000111100110011111111000000 -0000000088ffeeddeeeeeeeeeeeeeeeeeeeeffeeeeffffeeeeeeeeffffbb775566aaeeee -aa332233000088aa88888899bbaaaa99aabbaaaabbaabbbbaaaa88888877888877555555 -445577666655554455555566665544665533 -110000111111110011111111111111110000000000001100111111000011111111110000 -00000088ddddddddddffeeffeeeeeeeeeeeeffeeeeeeeeffeeeeeeeeeeffffffffffeedd -eecc441111002288997788aa99aaaa99aa99aabbbbaabbaaaa9977778888777777776655 -555577776666666666666677775555555555 -001111110011001100111111112211111100110000000011110011111111001111000000 -000022aaddccddddeeeeeeeeeeeeeeeeeeeeeeeeeeffeeffeeeeeeffeeffeeeeeeeeeeee -eeffdd3311110044998899999999aaaaaaaaaabbaabbbbaaaa8888778877888866776677 -665566667755556644665555554444666666 -110011110011111111001100002211111100110011111100111100111111111100000000 -000022bbcccccccceeeeeeeeeeeeeeeeeeeeffeeffeeffffffeeeeffeeffeeffeeeeeeee -eeddeebb6644000088998899bbbbbbaabbbbbbaabbbbbbcc999988888877888877667777 -557777777766665544555555555555665566 -110011221111111111111111111111221100001100110011111111221100221100000000 -00001199aabbccccddeeeeeeeeeeeeeeeeeeeeeeffffeeffeeffeeeeffeeffeeeeeeeeee -eeddeeeebb88110066aa99aabbccbbaabbbbbbaabbbbbbbbbb99aaaa9988777766667777 -666677777777665544665566555566664455 -221111222222111111111111221111111111111111001111111100221122221100000000 -000022aabbbbaaccddeeeeeeeeddeeeeeeffeeeeeeeeffeeffeeffeeffffeeeeeeeeeeee -eeeeeeeeeecc220066aaaaaaaabbbbbbccaabbaaaabbccbbaaaaaa998888886677887777 -777777888866776655667755665566666655 -222211222222111122111122111111000000001111111111111122111122220000000000 -00002299bbaaaabbddeeeeeeddeeffeeeeeeeeeeffeeeeeeeeffeeeeffffffeeeeeeeeee -eeeeeeeeeecc330044aaaabbaabbbbbbaaaabb99aabbbbbbbbaaaa889988888877888888 -887777778888776644777777666677667766 -222222332233222211221111221111110000111111222222222211222222221100000000 -00001188cc99aabbddddddeeeeeeeeeeeeeeffeeeeeeeeeeffeeeeffeeffeeeeeeeeeeee -eeeeeeeeeeee440044bbaabbbbaabbbb9999aaaabbaabbbbbb9999998888887788888899 -887777778888887755776677667755667755 -221122442222222222332211222222111111001111222222221133112222220000000000 -00001177bbaaaaaaeeddeeddeeeeddeeeeeeeeeeeeeeeeeeffeeffffeeeeeeffeeeeeedd -eeeeffeeddffaa0022aabbbbbbbbbbaaaa99bbbbaabbaabbaa9988888888998888887777 -888866777788888888888877666655445566 -331133442233333333332222332211111111111111112222222233221122220000000000 -0000115599aabbccddddeeddeeeeeeeeeeeeeeeeffeeeeffeeffeeffffffeeffeeffddee -eeeeeeeeeeffdd110088bbbbbbccbbaa99bbaabbaaaabbbbbbbb99888888888888666677 -777777778888666677888877775544444455 -332222332222334422222233222233110011222222112233223322222211221100000000 -000000228899aabbddddeeddeeeeeeeeeeeeeeeeffeeeeeeffeeffeeeeffeeffeeeeeedd -eeffeeeeeeeecc220066bbaabbbbbbaaaa999999aaaaaaaa9999aaaa9988888877776688 -888877778888776677887777666666665544 -333311332233333333222222222233331111113322222222223322332222220000000000 -000000225577aabbccddddddeeeeeeeeeeeeeeeeeeeeeeffffffffeeffffeeeeeeeeeeee -eeeeeeeeeeeedd110044bbaaaabbaabb99999999aabbaa999999aa999999998888777788 -888855888888886677777788777777555555 -222211222222224444111122222211222233221133443344332233333322551100000000 -00000022557788aaccddeeddddeeddeeeeeeeeeeffffeeffeeeeffeeeeeeeeffeeffeedd -eeeeeeeeeeeedd33003399aaaabbbbaaaa88999999aaaaaa99aaaabbaaaaaa9999778888 -887766888888885577776666777766556644 -222211222222222233334422222222112233222233554444332222222222440000000000 -0000001144779988bbccddddddffddeeeeeeffeeeeeeeeffffffeeeeeeffeeffffeeeedd -eeeeeeeeeeeedd2200228899aaaaaa88888899999999bbaa99aabbbbbbaa999988888888 -887777778877665566886666666677775566 -443322111133331111222233332222332222332233223333333333332233331100000000 -000000115555668899ddddddddeeeeeeeeffeeffffffeeffeeeeffeeeeeeeeeeeeeeeedd -eeeeeeeeeeeedd2200339999aabbaa889999aaaa99aabbaaaa99bbbbaaaa998899998888 -888888997777775577777777777777666666 -332211223322222222221122223333221122112233333333332244333333330000000000 -0000000033444466aaccccddddeeeeeeeeeeeeffeeeeeeffeeeeeeeeeeffeeeeffffeedd -eeeeeeeeeeeecc2200228899aaaa9988aaaaaaaa99aa99bbaabbaaaa99999988aa999988 -888888887777776677666666776666556644 -332222222233222233332222333333331133332233224433333344554444331100000000 -000000110044777788aaeeeeddeeeeddddddeeeeeeeeeeffeeffeeeeeeeeeeeeeeeedddd -ddeeddeeeeeedd220011aa9999aa999999bbbbbb99bbbbbbbbbbbbaaaaaa999999888899 -998888888888666677556677666655555555 -332222222222333333443333333322443333443344334433444455553333330000000000 -000000002233557788ccccccccaa775555446688ccddcceeeeeeeeeeddeeeeeeeeeedddd -eeddeeeeeeeedd44003399aa88aaaa99aaaaaaaa99bbbbbbbbbbbbbbbbbbaa999999aa88 -888866887788775577667755556655555544 -331122332222444433333333223333333344444444554433445555664444441100000000 -00000000332244889999777788330000000000116688aaddccddddccddddaa88aa99aadd -ddddeeeeeeddee660022aa99999999bb99bbbbaaaabbbbbbbbccbbbbbbbbaa99aaaa8888 -888877776677667755777755445555556655 -331122333333335544554433333322443344555555554433334433556655441100000000 -000000000000225544221100110000000000001111557799ccbb88778877110011003388 -bbddeeeeeeddee55002299aa999999aaaabbaabbaabbbbbbaaaaaabbaaaabbaa99998888 -887777667788666666666666555555554444 -333333333322444444555555444444444455556666555544334455336666551100000000 -000000001111001100000000000000000000000011224455889966111111000000000011 -66aaddeeeeeeee550033aa99aa999999bb99bbccaabbbbaaaaaaaabbaaaabbaabb888888 -667777777777775577554455553344444444 -223344332233555544556666665533335544556655555533446655555555661100000000 -00001100111100000000000011000000000000000011449999bb77000000000000004433 -225588cceeeeff660044aaaa888899aa9999aaaa99aabbaaaaaa99bbbb9999aaaa998888 -886677777777667766555555443355554455 -443344332233556655666655666633555544555555555555555566555555662200000000 -0000001111110000000000001100000000000000000066ddeeee990000000000000066bb -bb88bbcceeeeee880066aaaa9999bb9999aa99998899aa999999aaaabbaaaaaa99889988 -778888776677666655444455665555554433 -443333442233445577665566666655444444666655667766666666666644443300000000 -0000001133220000000000000000000000000000000055eeeeeebb110000000000000022 -bbffddddeeeeff88007799999999aabbaa9999999988aa99999999bbaaaa888877888888 -887777777766666655664455554455443344 -444422335566557766776666555544444455556666555555556666668899aa5500000000 -0000002233220000000000000044110011110000000055ffeeffcc110000000000000000 -0077ddddddddeebb118899999999aaaaaa8888aa88aaaaaa9999aabbaaaa997755889988 -887766777766775555665555444444443344 -555544333344556666556666445566556666555555665566665555335566999922000000 -0000002244332200000000001177663366330000000088eeeeffdd110000001100112200 -000066cceeeeeebb66ccbbaa9999aaaa998899aaaabbbbaa9988aaaabb99998888888877 -777755776666666655555555554444444444 -445555554444555555557766445544666677665566666666776611000000002233000000 -00000022445544112233442255442211110000000033bbeeeeeeee880000002255999966 -330033ddeeeeeeddddeeeeffccaa99998899aaaabbbbaaaa999999999999999988888877 -777766665566666655665544444444553333 -444444556666445555776666555566667777775566666655665500000000000000000000 -00000000334433337799999988775533112244225599ccddeeeeffee885533111166bbcc -bb6666ddffeeeeeeeeeeaa66aa99aa889999bbbbbbbb99aa999999999999998888888877 -667766555555555555444433444444333322 -334444445577665555556666665566665577666644444466664400000000000000000000 -000000002255667788bbbbbbaabb998866556688aabbddeeeeeeeeeedd8888bbaaccddee -eeeeddeeeeeeddeebb22000066aa88aabbaaccbbaa99aa99889988999999889999888877 -777766666666665544334455443333333333 -333355444466557766776655555555556666664455446666665500000000000000000000 -0000000011335577aaccddddddccbb998899ccddddccddeeffeeeeeeeedd8899ddeeeeee -eeddffeeeeeedddd3322220066aaaaaabb99bbbb99aaaa88888899888888888877887777 -556688553355665533444433334433333344 -444444225555445566888866666666777777776666556666664400000000000000000000 -0000000011224477aaddddeeddddddddddddddddddddeeeeeeffeeeeeeeecc88aaddeeee -eeeeeeeeeeeeeecc66dd8800779988bbbbaabbbbaaaa9988888888999977776677776666 -557766553355556644443333333344221133 -77bbccbb9988774455667777667788888877886666667777666611000000000000000000 -0000001111335577bbccddddeeeeeeddeeeeddddccddeeeeffeeeeeeeeeeffddddddeeee -eeeeffeeeeeeddccddeedd22999988aa99aaaa8899aa9988888888888888776677777766 -776666665555555544444444332222112211 -bbeeffffffeeeedd88444455668899998866776666666677775533000000000000000000 -0011114433446688bbccccccddddeeeeddddbbddeeddeeeeffffeeffeeffeeffffffeeee -ffeeeeffeeeeeebb77eeee88cc889999aaaa99aa99998888778888888888668888997777 -777777667766665533334433332222222222 -77ddeeffeeffeeeeee995555557788888888776677775577776655221100000000001100 -1122225555665588aabbbbccddddddeeccaabbeeddccddeeeeeeffeeffeeeeeeffeeeeee -eeffeeffeeeeffcc33bbeeeebbaaaaaa99aaaa9999888877889999999988777788887777 -888866556677665533334433112211222222 -4499bbbbeeeeeeeeeeee6633667799889988778877667788777777332200110000001100 -444477888866667799aabbccccddddddbb8888aa7755779999bbddeeffffeeeeeeffeeee -eeddeeeeffeeeedd44bbeeeebbaaaa99aaaaaa99889999888888aa99aa88776677888877 -887777666666554433554422222222222211 -003322446677cceeeeeeaa66777788888888888877667788887788662211113300002222 -66887777665566667799aabbccccccaa88443322000011223344446677ccffeeeeeeeeff -eebbeeeeeecceeeeaacceeeebbbbaaaaaabbaabbaa999988778899998888888888778888 -777766776677665555442222222233222222 -00220000000066ccffeeffaa776677887777887777777788888877773311005566115533 -7788996666445566667799bbccbbaaaa9933000000000000000000000066ffeeeeffeeee -eeddeeffeeffeeffeeddeeddbbaaaa99aaaaaabbccaaaa88889988999988888877888877 -888877667766666644332244442222223322 -1111000000000044aaeeffdd777755777788778877777788888888776611221122888844 -88aa77776655445555778899aa7788aaaa44000000000000000000000077ffeeeeddeeee -eeeeeeeeeeeeeeeeeeeeffccaaaaaa9999aaaaaabbaaaa9999888899bb99888866778888 -777777665555554444333322222222221122 -22000000001111001177dddd999999886666888877887788778888888844115544aa8888 -9988888866555555446666666666bbcc99330000000000000000000055eeffeeeeccddee -eeeeeeeeffeeffeeeeeeeeccaaaabbbbaaaabbbbaaaaaa88889999aa8899886688777766 -778888775566554433332233333322331111 -4400000000443300000033bbffeeffeebb666677888888888888777766663333bbbb88bb -aa998888885555554444221144aaccbb330000000000000000000033ccffeeeeffddcccc -cceeeeeeeeffeeeeeeffeebbbbbbbbbbbbaaaaaaaabbaa8899aa99889999888877888877 -667777668888998844332244442244332222 -770000000077ccbb996677eeeeeeeeeeeebb5566777788889988777777777755ccbbaacc -bbaa9988775577664400000055bb6633110000000000000000000077bbddeeeeeeffddaa -bbddddddddddffeeffeeeebbbbccccbbbbbbaaaaaaaa8888888888998899888888888888 -776677aaddeeeedd77223344443344333311 -dd77000011aa99aaddeecccceeeeeeeeeeeebbaa6677888899887788778888cceeccbbbb -ccaa998888888855110000337733000000000000000000000000005599ddccddeeeeeedd -aa99ccddaacceeffeeeeeeeebbaaccbbbbaa99aa99998888887799998899998877888888 -8888cceeeeeeeeddbb553344333333333322 -eeee88000077220033998866aaeeeeeeeeeeeeeeaa777788aa8899997788aaddccbbcccc -ccbbaaaabb9977440000335522000000000000000000000000000000227788aaeeeeeeee -bb8899ccddaaaaeeeeeeeeffcc99aaaa99999999aaaa8888888888777777888877777788 -88cceeeeeeeeddeeeeaa3344444433443333 -eeeedd55004488000011110077ffeeeeeeeeeeeeffbb8877889988999999ddddddddddcc -ddccccbb8866332200113300000000000000000000000000000000000000334488cceeee -ddccaa88bbbb6655bbffeeeeeeccaa9999aaaa99998899997777889999aa998888888866 -3388ddddddddcc88ccdd9944334433443322 -eeeeee88110066110000000088eeeeeeeeeeffeeeeeecc9977889999aacceeddeeeedddd -ddddaa88663300000000000000000000000000000000000000000011000000000022aadd -eeddccbb99aa88111188eeffeeffddaa99aaaaaa88998888888888aaeeeeeebbbbddddaa -1155ccaa55443311aaeedd88222222332211 -ddccdd88440000000000000077ddeeeeeeeeeeffeeeeffeebb99aaaaccddeeeeeeeeeeee -ddbb777777442200000000000000000000000000001188ccbb9999bb8833000000002222 -77ddddddccbb8844000044ddffffffeeaa88aa9999998888888888cceeddeeddeeeeeedd -2288bb991100000066bbddcc551122222222 -cc666622221100000000000055ddeeeeeeeeeeeeeeeeeeeeee9999ccddeeeeffeeeeeeee -eeddccaa884422331100000000000000000000001177eeeeeeeedddddd99550000001133 -1155ddeeddddcc8855000033aaeeeeffdd9999aa9999aa88995555cceeeeddeeeeeeeebb -00559999440000000055bbddbb3322223322 -ffdd4400001100000000000044ddeeeeeeeeeeeeeeeeeeeeeeccbbeeffeeeeeeeeffeeee -eeddeeccbb8866772200000000000000000000001144668899aabbddddccbb66110044bb -bbbbcccceeeeddddcc8877332277cceeeeeebb88999999aadd7799eeeeeeeeeeeeddddaa -4444775577220000000044bbee7711222211 -eeeecc33000000000000000033cceeeeeeeeeeeeeeeeeeffeeffeeffeeeeffeeffeeffff -eeffeeddeeccbb884411000000000000000011000000000000000088ccddddaa6644bbee -ddffeeddeeeeeeeeeeffffeeddbbddeeffeeeeddaa88aaccddbbeeddeeddddeeeeee8844 -7711221100000000001177ccddbb44112211 -eeeeffaa000000000000000066eeeeeeddddeeeeffeeeeeeffeeeeeeffeeeeffeeeeffff -eeeeeeeeeeeeeecc66110000000000000022666655334433446688bbeeddeeddbbccddee -eeeeeeeeeeddeeeeffffeeeeffffffeeeeeeeeffdd99cceeddbbddeeddddeeddeecc2200 -22000000000000003399ccccdddd88111122 -eeeeeeee550000000000000088eeddddddccddddeeeeddeeeeeeeeeeffeeffeeeeffffee -ffffeeeeffeeeeee99220000000011336688bbddddddddeeeeffeeeeeeeeeeeeeeeeeeee -ffeeffeeeeeeeeffeeeeeeffeeffeeeeffeeeeeeffddddeedd99ccddddddeeeedd660000 -00000000000000001166ccddddeeaa222222 -eeeeeeee880000000000000099eecc888888ddccccaa88ccddeeeeeeeeeeffeeffeeffee -ffeeeeffeeeeeeddbb3300001122336688aaddeeeeddeeeeeeeeeeffffeeeeffeeeeeeee -eeffeeffeeeeeeeeeeffeeeeffeeeeeeeeeeeeeeeeccccddcc5588aacceeddeecc220000 -0000000000000000004499bbccddcc331111 -eeeeeeee990000000000000088ddccdd6622bbddbb4455ddbbaaeeeeffeeffeeeeeeffff -eeffeeeeeeeeddcc996633335522335588aaccddeeeeeeeeeeeeeeeeeeffeeffffeeeeff -ffeeeeffffeeeeeeeeffeeeeeeffeeeeeeeeeeeeff99779988003377ccddeeee99000000 -000000000000000000000055bbddcc441122 -ffeeeeeedd3300000000000077cceeee880044aabb55ccffddccddffeeeeffeeeeeeeeff -eeffeeeeeeddccbb776644442211223377aaccddeeeeeeeeeeeeffffffeeffeeeeeeffee -ffeeeeeeeeeeeeffffeeeeffeeeeffffeeffeeffff8811333300001199ddeeee66000000 -0000000000000000001155ccddccdd551111 -eeeeeeeedd991100000000000077ccdd555577111133ddffeeddddffffffeeffffffeeee -ffffeeeeffddccbb7733110000000011336688bbcccceeeeeeeeeeffeeeeffffffeeeeee -ffeeffeeffeeffeeeeffeeffeeffffeeffeeffeeff99000000000066ddddeecc22000000 -00000000000000004499ccdddddddd771122 -eeeeeeeeeedd6600000000000000226677ddee66000088bbcc8866777799ccbbaabbbbcc -ddeeffffffeeeeeebb6644110000000000113355668899bbbbddddddeeeeeeddeeeeeeff -eeeeeeeeeeeeeeffffeeffffeeeeddddccddddddee990000000000aaffeeeeaa00000000 -00000000000000005588bbccccdddd880011 -eeeeffeeeeeebb99220000000000000055bbaa3300000011220000003399aa9988886666 -66888888bbddeeeeeeddcc9933000000000000000011224466778888aabbddddeeeeeeee -ffffeeffffeeeeeeccbbbbaaaa777777774411222211000000000055aaaaaa6622000000 -00000000000000004499bbccddddee991111 -eeeeeeffeeddddcc4422220000000000001133000000000000000000669999aaaa99aa99 -999911000011445588aacccc88110000000000000000222222223322336699bbddeeffee -ffeeeeddccccccaaaaaaaabbbbaabbbbbb66000000220000000000001111110000000000 -000000000000001155aabbddccddddbb2211 -ffeeffeeeeeecccc99aa55000000000000000000000000000000001188888899aaaaaaaa -99770000000000000000113333000000000000000000000011000000002277cceeeeddaa -8888ccccccccccccbbbbccddbbbbbbbbcc88000000000000000000000000000000000000 -00000000000000116699ccddddddeecc2211 -eeeeeeeeeeeeddccddccbb661100000000000000000000000000227788778877889999aa -660000000000000000000000000000000000000000111100000000000011445544331100 -0088ccccccccccccccbbbbccccbbbbbbaa99110000000000000000000000000000000000 -000000000000002266aaccddddddddcc3300 -eeeeeeeeeeeeddddbbccccccaa88887788aa440000000000004488778888887788779977 -110000000000000000000000000000000000001111111111001111000000000000000000 -55ccccbbccccbbccccbbbbbbbbbbbb999999772200000000000000000000000000000000 -000000000000002277aaddddccccdddd5511 -eeeeeeffffddddddddddeeddddeeddeeddcc773311000000337766777777667766776611 -000000000000000000000000000000000000000000000000000000000000000000000055 -ccbbbbccbbccccbbbbbbbbbbbbaaaaaaaa99997711000000000000000000000000000000 -000000000000001166aabbccccdddddd7711 -eeeeffeeeeeeeeeeeeddeeddeeddddddccbb996611001144777777776677776666771100 -0000110000000000000000000000000000000000000000000000000000000000000022dd -8844ccbbbbaabbaabbbbaabbaaaaaa99aa99aa7766110000000000000000000011557777 -66330000000000003388aaccdddddddd9911 -ddeeddeeeeeeeeeeddeeddddeeddddccbbaa883300004466667777666655666688440000 -0000001111000000000000000000000000000000000000000000000000000000000099ff -aa0077bb99aabbbbbbbb99aaaa99999999aa887766440000000000000000003388bbccbb -cc773300110000002277bbbbccccddddaa22 -ddeeddeeeeeeddeeeeddddddddddddbb9988330000336655886688776655556688220000 -00000011222211000000000000000000000000000000000000000000000000000077eeff -bb001199ccbbaaaaaaaaaa889988999999997777777733000000000000001166aaccccdd -ccbb770066550000336699ccddccdddddd55 -99aabbddddeeddeeddddddcceeddcc887755110011556666667777776677775522000000 -000011224455441100000000000000000000000000000000000000000000000066eeeeee -cc0000338899bb999999999988888888aa998888777755000000000000002277bbccccdd -ddcc991177882200336699bbddccddddddaa -22333366ccddddddddccddbbaa9977333311001144666655666688889966330000000000 -0000115555777777551100000000000000000000000000000000000000000044ddeeeeee -ee220000002277aabbaaaaaa99888899aa99aa88777766220000000000000055aaccddcc -ddcc991133885522113388ccccddddccccdd -0000000088aa888888887733221100000000115566776677777799994411000000000000 -00001155777788998877773300000000000000110000000000000000000077cceeeeeeee -ee2200000000003377aabbbbaaaa9988aaaaaa999977665500000000000000117799aabb -ccbb883311443311112266bbccccdddddddd -000000002233001122111100000000002244667766668866888899220000000000000000 -000000777799aaaa99aaaa99550000000000000000000000000000003388ddeeeeeeffee -ee33000000001100003388ccbbaa99999999999988775566330000000000000011558899 -aa9977220011000011335588ccddddeeddee -00000000000000000000000000001144667766667788aa99aa8811000000000000000000 -0000003377aabb99bbbbccaa77663300000000000000000000000055cceeeeeeeeeeeeff -ee3300000000001100000055aaccaaaa9988778888887755553300000000000000115566 -776622000000000000113377bbddccdddddd -00000000000000000000000000336677777788777788aa99661100000000000000000000 -000000117799aaccccccccbbbbaa99440000000000000000002288ddeeeeeeeeffeeeeee -dd22000000000000110000002288aaaaaa99778888778877776644000000000000002222 -22110000000000000000003388aaccddddee -000000000000000000000022667777887788777799884411000000000000000000000000 -0000000077aabbccddddccccddccddbb88442200000000000088ffeeeeeeeeffeeeeeeff -dd1100000000000000110000000044aabbaa999999888888665566440000000000000000 -0000000000000000000000001155bbccdddd -000000000000000022556688776688888877887733000000000000000000000000000000 -0000000055bbccddccddddddddeeeedddddd8800000011110000bbffeeeeeeeeffeeeeff -dd1100000000000000001100000000224444667777778888887766555500000000000000 -00000000000000000000000000003388ccdd -000000001133558899998888887788998899660000000000000000000000000000000000 -0000000022aaccddddddeeeeeeeeeeeeeedd330000117766447733ddeeeeffeeeeeeeeff -aa0000000000000000000000000000000000000000113344667788887766110000000000 -000000000000000000000000000000117799 -0000446688aabb88aa999988998888999977000000000000000000000000000000000000 -0000000000aaccddeeeeeeeeeeeeeeeeffaa00000044dd7788ee77aaeeffeeeeffeeffff -880000000000000000000000000000000000000000000000001122222233441100000000 -000000000000000000000000000000000033 -777788aa9988888888888899aa8899886600000000000000000000000000000000000000 -000000000088ddeeeeeeeeeeeeeeeeffeeaa550066bbdd99cceeccaaffeeeeeeeeffeeff -550000000000000000000000000000000000000000000000000000000000113322000000 -000000000000000000000000000000000000 -884422331100000000000022331100000000000000000000000000000000000000000000 -000000000077ddeeeeeeffeeffffffffbbaa6611aaddeecceeeeeebbeeffeeffffeeffee -440000000000000000000000000000000000000000000000000000000000000022110000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000077ddeeeeeeeeffeeeeffcc1111113399bbee88cceeee99aaffffeeffeeeeee -330000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000044ddeeeeeeeeffeeeeff66002266001166ee66aaeeee6666ffeeeeeeeeffdd -110000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000022ddeeeeeeeeeeffffcc11001155003388eeddddeebb2211ddffeeffeeffcc -110000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000aaffeeeeffeeeeff8800000088221155cceebbbb55000088ffeeeeeeffcc -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000077eeeeeeeeeeeeee3300000088660055ccdd554411000044ffffffeeffbb -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000022ddffeeffffff990055330055990077dddd221111330011ccffeeffff88 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000bbffeeeeeeee442299770022aa0077dddd442266bb9944aaffeeffff88 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000066ffeeeeff882288ddaa000077331188993399eeeeffcc99eeeeeeff77 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000011ddffeeffaa99ddeecc11001111001199bbeeeeeeeeeebbddffeecc11 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000066ffeeeeffeeeeeeee2200000066bbddeeeeeeeeeeffddcceebb5500 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000055ddeeeeeeeeffee550055aaaacceeccddffffeeeeeeeeeeffcc00 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000aaffeeffeeeeee66337788bbeeeeeeeeffeeffeeeeeeeeffcc00 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000033cceeeeeeeeeeee440066ddeeeeeeeeeeeeeeeeffeeffeeffbb00 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000055eeeeffeeffeeee88aacceeddeeeeeeeeeeeeffeeeeffeeff8800 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000011ddeeeeeeeeeeeeddddddeeeeeeeeffeeeeffeeffffeeffff6600 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000088ffeeffeeeeeeeeeeddeeeeeeffeeeeeeeeffeeeeffeeff4400 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000033eeeeeeffeeeeeeeeeeffeeeeeeeeeeddeeeeeeeeffeeee3300 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000011bbffeeeeffeeddeeddddbbaaaaddddcceeffeeffeeffee2200 -000000000000000000000000000000000000000000000000000000002200220000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000088ffeeeeeeddddcc9999aaaaddeeeeeeffeeffeeeeffcc0000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000044eeffeeffccddddccddeeeeeeeeeeeeeeeeeeffffffaa0000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000099ffcc5544cceeddddeeddccddeeddddeeeeeeeeff990000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000044ff9911004499aabbccccccccddbbaabbccddffff660000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000011ccbb996655bbbbaaccbbbbddddaaaaccddcceeee550000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000006688000066ddcccceeeeeeeeffeeddccaabbeeff330000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000001144000066eeeeeeddccbbbbbb7722220022bbee110000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000022665599aaccbbaabb775588778899cc000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000002211001177bbddbbaabbaa99ddeedd8844000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000110077bbddddeeffeeeeffeeffaa00000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000088aaeeffeeddccbbcc776655996600000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000778877555533445588113355882200000000 -441100000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000007799ccccddbbddeeee3300000000 -331100000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000001155bbeeeeeeeeffeeeeeeff5500000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000004488ddeeeeeeeeeeeeeeeedd2200000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000033bbddeeeeeeffeeeeffaa0000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000000000088ccddeeeeeeeeeeff880000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000000000044aaeeeeffeeeeeeff550000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000001188ddccccddbb9988000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000022222233774422000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000000000000116699aaccddbb44000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000002288888888992200000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000002255661100000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000011000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000113355882200000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000011778899771100000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000002244110000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000110000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000001100 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000001100 -000000000000000000000000000000000000000000000000000000000033110000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000022440000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000011220000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000001100000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000001100000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000001100000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000110000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000001100000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000 -001100110011001100110011001100110000000000000000000000000000000000000000 -000000000000000000000000000000000000000000221100000000000000000000001111 -110000001100001100110000110000000000000000000000000000000000000000001100 -001100000000000000000000110000001100 - -showpage - -% stop using temporary dictionary -end - -% restore original state -origstate restore - -%%Trailer diff --git a/lib/docbuilder/doc/src/notes.xml b/lib/docbuilder/doc/src/notes.xml deleted file mode 100644 index 95f24ea9ca..0000000000 --- a/lib/docbuilder/doc/src/notes.xml +++ /dev/null @@ -1,256 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2007</year><year>2011</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>DocBuilder Release Notes</title> - <prepared>otp_appnotes</prepared> - <docno>nil</docno> - <date>nil</date> - <rev>nil</rev> - <file>notes.xml</file> - </header> - <p>This document describes the changes made to the DocBuilder - application.</p> - -<section><title>Docbuilder 0.9.8.11</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The docbuilder application has been deprecated and will - be removed in the R15 release.</p> - <p> - Own Id: OTP-9509</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.10</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> fop 1.0 crashed when building the docbuilder pdf with - the following message - "java.lang.IllegalArgumentException: factor < 0; was: - -1". <br/> This is a known bug in fop 1.0 (fop bug id: - Bug 50524) when there is a word that consist of a single - soft hyphen (&shy;). this has been fixed in fop - source archive but not it's not in a release yet. It's - fixed in our documentation by removing the soft hyphens - where this is a problem. </p> - <p> - Own Id: OTP-9143</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.9</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> Fix compatibility issues with docbuilder for R11 - documentation patches. </p> - <p> - Own Id: OTP-8946</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.8</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> Fixed problem with a centered table that was - transformed into an xml document which then produced - mis-formatted html. </p> - <p> - Own Id: OTP-8784</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.7</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>The documentation is now possible to build in an open - source environment after a number of bugs are fixed and - some features are added in the documentation build - process. </p> - <p>- The arity calculation is updated.</p> - <p>- The module prefix used in the function names for - bif's are removed in the generated links so the links - will look like - "http://www.erlang.org/doc/man/erlang.html#append_element-2" - instead of - "http://www.erlang.org/doc/man/erlang.html#erlang:append_element-2".</p> - <p>- Enhanced the menu positioning in the html - documentation when a new page is loaded.</p> - <p>- A number of corrections in the generation of man - pages (thanks to Sergei Golovan)</p> - <p>- The legal notice is taken from the xml book file so - OTP's build process can be used for non OTP - applications.</p> - <p> - Own Id: OTP-8343</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.6</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The documentation is now built with open source tools - (xsltproc and fop) that exists on most platforms. One - visible change is that the frames are removed.</p> - <p> - Own Id: OTP-8201</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.5</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>The copyright notices have been updated.</p> - <p> - Own Id: OTP-7851</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8.4</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - The element "code" with multiple CDATA or CDATA plus - other data now works as expected, previously it caused a - crash.</p> - <p> - Own Id: OTP-7236</p> - </item> - </list> - </section> - -</section> - -<section><title>Docbuilder 0.9.8</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The generated html should now be valid xhtml (with a few - exceptions to be fixed in next version).</p> - <p> - Own Id: OTP-7027</p> - </item> - </list> - </section> - -</section> - - <section><title>Docbuilder 0.9.7</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - New fonts and new CSS style included in generated html documents. - </p> - </item> - <item> - <p> - Updated DTD's with new header elements copyright and legalnotice. - Element authors changed to optional instead of mandatory. - - </p> - </item> - </list> - </section> - </section> - - <section><title>Docbuilder 0.9.1</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Line breaks within <c>pre</c> are now always preserved.</p> - <p> - The definition of <c>name</c> in the cref DTD is now - correctly handled.</p> - <p> - <c>docb_transform</c>: The HTML snippet returned by the - <c>Module:head()</c> callback function is now placed - below the title in the HTML file (as specified in the - documentation), not on the same line.</p> - <p> - <c>docb_gen</c>: Added option <c>sort_functions</c>.</p> - <p> - Fixed bugs in cites and terms DTD, and also in book, - bookinsidecover and report DTDs which are not officially - supported (yet).</p> - <p> - License info added to all DTD files.</p> - <p> - Corrections and clarifications made to the User's Guide.</p> - <p> - Own Id: OTP-6775</p> - </item> - </list> - </section> - </section> - - <section> - <title>DocBuilder 0.9</title> - <p>First version of DocBuilder released as part of Erlang/OTP. - Previously it has been used as an internal tool only.</p> - </section> -</chapter> - diff --git a/lib/docbuilder/doc/src/part_notes.xml b/lib/docbuilder/doc/src/part_notes.xml deleted file mode 100644 index 2f824630fb..0000000000 --- a/lib/docbuilder/doc/src/part_notes.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>2007</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - 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 online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>DocBuilder Release Notes</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <description> - <p><em>Docbuilder</em> provides functionality for generating HTML - documentation for Erlang modules and Erlang/OTP applications - from XML source code and/or EDoc comments in Erlang source code.</p> - </description> - <xi:include href="notes.xml"/> -</part> - diff --git a/lib/docbuilder/dtd/Makefile b/lib/docbuilder/dtd/Makefile deleted file mode 100644 index 05c656f3fc..0000000000 --- a/lib/docbuilder/dtd/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# ``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 -# ---------------------------------------------------- - -DTD_FILES = \ - application.dtd \ - appref.dtd \ - book.dtd \ - bookinsidecover.dtd \ - chapter.dtd \ - cites.dtd \ - common.dtd \ - common.entities.dtd \ - common.header.dtd \ - common.image.dtd \ - common.refs.dtd \ - common.table.dtd \ - comref.dtd \ - cref.dtd \ - erlref.dtd \ - fascicules.dtd \ - fileref.dtd \ - part.dtd \ - report.dtd \ - terms.dtd \ - xhtml-lat1.ent \ - xhtml-special.ent \ - xhtml-symbol.ent \ - xhtml1-frameset.dtd \ - xhtml1-strict.dtd \ - xhtml1-transitional.dtd - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: - -clean: - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: - $(INSTALL_DIR) $(RELSYSDIR)/dtd - $(INSTALL_DATA) $(DTD_FILES) $(RELSYSDIR)/dtd - -release_docs_spec: - - - - - - - diff --git a/lib/docbuilder/dtd/common.dtd b/lib/docbuilder/dtd/common.dtd deleted file mode 100644 index 2c4ad51ab1..0000000000 --- a/lib/docbuilder/dtd/common.dtd +++ /dev/null @@ -1,87 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!-- This file contains common stuff for all dtds. --> - -<!ENTITY % common.entities SYSTEM "common.entities.dtd" > -%common.entities; - -<!ENTITY % block "p|pre|code|list|taglist|codeinclude| - erleval" > -<!ENTITY % inline "#PCDATA|c|em|term|cite|br|path|seealso| - url|marker" > -<!-- XXX --> -<!ELEMENT p (%inline;)* > -<!ELEMENT pre (#PCDATA|seealso|url|input)* > -<!ELEMENT input (#PCDATA|seealso|url)* > -<!ELEMENT code (#PCDATA) > -<!ATTLIST code type (erl|c|none) "none" > -<!ELEMENT quote (p)* > -<!ELEMENT warning (%block;|quote|br|marker)* > -<!ELEMENT note (%block;|quote|br|marker)* > -<!ELEMENT c (#PCDATA) > -<!ELEMENT em (#PCDATA|c)* > - -<!-- XXX --> -<!ELEMENT term (termdef?) > -<!ATTLIST term id CDATA #REQUIRED > -<!ELEMENT termdef (#PCDATA) > -<!ELEMENT cite (citedef?) > -<!ATTLIST cite id CDATA #REQUIRED > -<!ELEMENT citedef (ctitle,cauthor,chowpublished) > -<!ELEMENT ctitle (#PCDATA) > -<!ELEMENT cauthor (#PCDATA) > -<!ELEMENT chowpublished (#PCDATA) > - -<!-- XXX --> -<!ELEMENT br EMPTY > - -<!-- Path --> - -<!ELEMENT path (#PCDATA) > -<!ATTLIST path unix CDATA "" - windows CDATA "" > - -<!-- List --> - -<!ELEMENT list (item+) > -<!ATTLIST list type (ordered|bulleted) "bulleted" > -<!ELEMENT taglist (tag,item)+ > -<!ELEMENT tag (#PCDATA|c|em|seealso|url)* > -<!ELEMENT item (%inline;|%block;)* > - -<!-- References --> - -<!ELEMENT seealso (#PCDATA) > -<!ATTLIST seealso marker CDATA #REQUIRED > -<!ELEMENT url (#PCDATA) > -<!ATTLIST url href CDATA #REQUIRED > -<!ELEMENT marker EMPTY > -<!ATTLIST marker id CDATA #REQUIRED > - -<!-- CodeInclude --> - -<!ELEMENT codeinclude EMPTY > -<!ATTLIST codeinclude file CDATA #REQUIRED - tag CDATA "" - type (erl|c|none) "none" > - -<!-- ErlEval --> - -<!ELEMENT erleval EMPTY > -<!ATTLIST erleval expr CDATA #REQUIRED > diff --git a/lib/docbuilder/dtd/common.refs.dtd b/lib/docbuilder/dtd/common.refs.dtd deleted file mode 100644 index 7b9974fbda..0000000000 --- a/lib/docbuilder/dtd/common.refs.dtd +++ /dev/null @@ -1,40 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!-- This file contains common stuff for the *ref.dtd files. - Note that `name' is defined in each *ref.dtd. --> - -<!ENTITY % common SYSTEM "common.dtd" > -%common; -<!ENTITY % common.header SYSTEM "common.header.dtd" > -%common.header; - -<!ELEMENT description (%block;|quote|br|marker|warning|note)* > -<!ELEMENT funcs (func)+ > -<!ELEMENT func (name+,fsummary,type?,desc?) > -<!-- ELEMENT name is defined in each ref dtd --> -<!ELEMENT fsummary (#PCDATA|c|em)* > -<!ELEMENT type (v,d?)+ > -<!ELEMENT v (#PCDATA) > -<!ELEMENT d (#PCDATA|c|em)* > -<!ELEMENT desc (%block;|quote|br|marker|warning|note)* > -<!ELEMENT authors (aname,email)+ > -<!ELEMENT aname (#PCDATA) > -<!ELEMENT email (#PCDATA) > -<!ELEMENT section (marker*,title,(%block;|quote|br|marker| - warning|note)*) > diff --git a/lib/docbuilder/dtd/erlref.dtd b/lib/docbuilder/dtd/erlref.dtd deleted file mode 100644 index 21656a1446..0000000000 --- a/lib/docbuilder/dtd/erlref.dtd +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common.refs SYSTEM "common.refs.dtd" > -%common.refs; - -<!ELEMENT erlref (header,module,modulesummary,description, - (section|funcs)*,authors?) > -<!ELEMENT module (#PCDATA) > -<!ELEMENT modulesummary (#PCDATA) > - -<!-- `name' is used in common.refs.dtd and must therefore - be defined in each *ref. dtd --> -<!ELEMENT name (#PCDATA) > diff --git a/lib/docbuilder/dtd/xhtml-lat1.ent b/lib/docbuilder/dtd/xhtml-lat1.ent deleted file mode 100644 index aaae738cfc..0000000000 --- a/lib/docbuilder/dtd/xhtml-lat1.ent +++ /dev/null @@ -1,196 +0,0 @@ -<!-- Portions (C) International Organization for Standardization 1986 - Permission to copy in any form is granted for use with - conforming SGML systems and applications as defined in - ISO 8879, provided this notice is included in all copies. ---> -<!-- Character entity set. Typical invocation: - <!ENTITY % HTMLlat1 PUBLIC - "-//W3C//ENTITIES Latin 1 for XHTML//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"> - %HTMLlat1; ---> - -<!ENTITY nbsp " "> <!-- no-break space = non-breaking space, - U+00A0 ISOnum --> -<!ENTITY iexcl "¡"> <!-- inverted exclamation mark, U+00A1 ISOnum --> -<!ENTITY cent "¢"> <!-- cent sign, U+00A2 ISOnum --> -<!ENTITY pound "£"> <!-- pound sign, U+00A3 ISOnum --> -<!ENTITY curren "¤"> <!-- currency sign, U+00A4 ISOnum --> -<!ENTITY yen "¥"> <!-- yen sign = yuan sign, U+00A5 ISOnum --> -<!ENTITY brvbar "¦"> <!-- broken bar = broken vertical bar, - U+00A6 ISOnum --> -<!ENTITY sect "§"> <!-- section sign, U+00A7 ISOnum --> -<!ENTITY uml "¨"> <!-- diaeresis = spacing diaeresis, - U+00A8 ISOdia --> -<!ENTITY copy "©"> <!-- copyright sign, U+00A9 ISOnum --> -<!ENTITY ordf "ª"> <!-- feminine ordinal indicator, U+00AA ISOnum --> -<!ENTITY laquo "«"> <!-- left-pointing double angle quotation mark - = left pointing guillemet, U+00AB ISOnum --> -<!ENTITY not "¬"> <!-- not sign = discretionary hyphen, - U+00AC ISOnum --> -<!ENTITY shy "­"> <!-- soft hyphen = discretionary hyphen, - U+00AD ISOnum --> -<!ENTITY reg "®"> <!-- registered sign = registered trade mark sign, - U+00AE ISOnum --> -<!ENTITY macr "¯"> <!-- macron = spacing macron = overline - = APL overbar, U+00AF ISOdia --> -<!ENTITY deg "°"> <!-- degree sign, U+00B0 ISOnum --> -<!ENTITY plusmn "±"> <!-- plus-minus sign = plus-or-minus sign, - U+00B1 ISOnum --> -<!ENTITY sup2 "²"> <!-- superscript two = superscript digit two - = squared, U+00B2 ISOnum --> -<!ENTITY sup3 "³"> <!-- superscript three = superscript digit three - = cubed, U+00B3 ISOnum --> -<!ENTITY acute "´"> <!-- acute accent = spacing acute, - U+00B4 ISOdia --> -<!ENTITY micro "µ"> <!-- micro sign, U+00B5 ISOnum --> -<!ENTITY para "¶"> <!-- pilcrow sign = paragraph sign, - U+00B6 ISOnum --> -<!ENTITY middot "·"> <!-- middle dot = Georgian comma - = Greek middle dot, U+00B7 ISOnum --> -<!ENTITY cedil "¸"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia --> -<!ENTITY sup1 "¹"> <!-- superscript one = superscript digit one, - U+00B9 ISOnum --> -<!ENTITY ordm "º"> <!-- masculine ordinal indicator, - U+00BA ISOnum --> -<!ENTITY raquo "»"> <!-- right-pointing double angle quotation mark - = right pointing guillemet, U+00BB ISOnum --> -<!ENTITY frac14 "¼"> <!-- vulgar fraction one quarter - = fraction one quarter, U+00BC ISOnum --> -<!ENTITY frac12 "½"> <!-- vulgar fraction one half - = fraction one half, U+00BD ISOnum --> -<!ENTITY frac34 "¾"> <!-- vulgar fraction three quarters - = fraction three quarters, U+00BE ISOnum --> -<!ENTITY iquest "¿"> <!-- inverted question mark - = turned question mark, U+00BF ISOnum --> -<!ENTITY Agrave "À"> <!-- latin capital letter A with grave - = latin capital letter A grave, - U+00C0 ISOlat1 --> -<!ENTITY Aacute "Á"> <!-- latin capital letter A with acute, - U+00C1 ISOlat1 --> -<!ENTITY Acirc "Â"> <!-- latin capital letter A with circumflex, - U+00C2 ISOlat1 --> -<!ENTITY Atilde "Ã"> <!-- latin capital letter A with tilde, - U+00C3 ISOlat1 --> -<!ENTITY Auml "Ä"> <!-- latin capital letter A with diaeresis, - U+00C4 ISOlat1 --> -<!ENTITY Aring "Å"> <!-- latin capital letter A with ring above - = latin capital letter A ring, - U+00C5 ISOlat1 --> -<!ENTITY AElig "Æ"> <!-- latin capital letter AE - = latin capital ligature AE, - U+00C6 ISOlat1 --> -<!ENTITY Ccedil "Ç"> <!-- latin capital letter C with cedilla, - U+00C7 ISOlat1 --> -<!ENTITY Egrave "È"> <!-- latin capital letter E with grave, - U+00C8 ISOlat1 --> -<!ENTITY Eacute "É"> <!-- latin capital letter E with acute, - U+00C9 ISOlat1 --> -<!ENTITY Ecirc "Ê"> <!-- latin capital letter E with circumflex, - U+00CA ISOlat1 --> -<!ENTITY Euml "Ë"> <!-- latin capital letter E with diaeresis, - U+00CB ISOlat1 --> -<!ENTITY Igrave "Ì"> <!-- latin capital letter I with grave, - U+00CC ISOlat1 --> -<!ENTITY Iacute "Í"> <!-- latin capital letter I with acute, - U+00CD ISOlat1 --> -<!ENTITY Icirc "Î"> <!-- latin capital letter I with circumflex, - U+00CE ISOlat1 --> -<!ENTITY Iuml "Ï"> <!-- latin capital letter I with diaeresis, - U+00CF ISOlat1 --> -<!ENTITY ETH "Ð"> <!-- latin capital letter ETH, U+00D0 ISOlat1 --> -<!ENTITY Ntilde "Ñ"> <!-- latin capital letter N with tilde, - U+00D1 ISOlat1 --> -<!ENTITY Ograve "Ò"> <!-- latin capital letter O with grave, - U+00D2 ISOlat1 --> -<!ENTITY Oacute "Ó"> <!-- latin capital letter O with acute, - U+00D3 ISOlat1 --> -<!ENTITY Ocirc "Ô"> <!-- latin capital letter O with circumflex, - U+00D4 ISOlat1 --> -<!ENTITY Otilde "Õ"> <!-- latin capital letter O with tilde, - U+00D5 ISOlat1 --> -<!ENTITY Ouml "Ö"> <!-- latin capital letter O with diaeresis, - U+00D6 ISOlat1 --> -<!ENTITY times "×"> <!-- multiplication sign, U+00D7 ISOnum --> -<!ENTITY Oslash "Ø"> <!-- latin capital letter O with stroke - = latin capital letter O slash, - U+00D8 ISOlat1 --> -<!ENTITY Ugrave "Ù"> <!-- latin capital letter U with grave, - U+00D9 ISOlat1 --> -<!ENTITY Uacute "Ú"> <!-- latin capital letter U with acute, - U+00DA ISOlat1 --> -<!ENTITY Ucirc "Û"> <!-- latin capital letter U with circumflex, - U+00DB ISOlat1 --> -<!ENTITY Uuml "Ü"> <!-- latin capital letter U with diaeresis, - U+00DC ISOlat1 --> -<!ENTITY Yacute "Ý"> <!-- latin capital letter Y with acute, - U+00DD ISOlat1 --> -<!ENTITY THORN "Þ"> <!-- latin capital letter THORN, - U+00DE ISOlat1 --> -<!ENTITY szlig "ß"> <!-- latin small letter sharp s = ess-zed, - U+00DF ISOlat1 --> -<!ENTITY agrave "à"> <!-- latin small letter a with grave - = latin small letter a grave, - U+00E0 ISOlat1 --> -<!ENTITY aacute "á"> <!-- latin small letter a with acute, - U+00E1 ISOlat1 --> -<!ENTITY acirc "â"> <!-- latin small letter a with circumflex, - U+00E2 ISOlat1 --> -<!ENTITY atilde "ã"> <!-- latin small letter a with tilde, - U+00E3 ISOlat1 --> -<!ENTITY auml "ä"> <!-- latin small letter a with diaeresis, - U+00E4 ISOlat1 --> -<!ENTITY aring "å"> <!-- latin small letter a with ring above - = latin small letter a ring, - U+00E5 ISOlat1 --> -<!ENTITY aelig "æ"> <!-- latin small letter ae - = latin small ligature ae, U+00E6 ISOlat1 --> -<!ENTITY ccedil "ç"> <!-- latin small letter c with cedilla, - U+00E7 ISOlat1 --> -<!ENTITY egrave "è"> <!-- latin small letter e with grave, - U+00E8 ISOlat1 --> -<!ENTITY eacute "é"> <!-- latin small letter e with acute, - U+00E9 ISOlat1 --> -<!ENTITY ecirc "ê"> <!-- latin small letter e with circumflex, - U+00EA ISOlat1 --> -<!ENTITY euml "ë"> <!-- latin small letter e with diaeresis, - U+00EB ISOlat1 --> -<!ENTITY igrave "ì"> <!-- latin small letter i with grave, - U+00EC ISOlat1 --> -<!ENTITY iacute "í"> <!-- latin small letter i with acute, - U+00ED ISOlat1 --> -<!ENTITY icirc "î"> <!-- latin small letter i with circumflex, - U+00EE ISOlat1 --> -<!ENTITY iuml "ï"> <!-- latin small letter i with diaeresis, - U+00EF ISOlat1 --> -<!ENTITY eth "ð"> <!-- latin small letter eth, U+00F0 ISOlat1 --> -<!ENTITY ntilde "ñ"> <!-- latin small letter n with tilde, - U+00F1 ISOlat1 --> -<!ENTITY ograve "ò"> <!-- latin small letter o with grave, - U+00F2 ISOlat1 --> -<!ENTITY oacute "ó"> <!-- latin small letter o with acute, - U+00F3 ISOlat1 --> -<!ENTITY ocirc "ô"> <!-- latin small letter o with circumflex, - U+00F4 ISOlat1 --> -<!ENTITY otilde "õ"> <!-- latin small letter o with tilde, - U+00F5 ISOlat1 --> -<!ENTITY ouml "ö"> <!-- latin small letter o with diaeresis, - U+00F6 ISOlat1 --> -<!ENTITY divide "÷"> <!-- division sign, U+00F7 ISOnum --> -<!ENTITY oslash "ø"> <!-- latin small letter o with stroke, - = latin small letter o slash, - U+00F8 ISOlat1 --> -<!ENTITY ugrave "ù"> <!-- latin small letter u with grave, - U+00F9 ISOlat1 --> -<!ENTITY uacute "ú"> <!-- latin small letter u with acute, - U+00FA ISOlat1 --> -<!ENTITY ucirc "û"> <!-- latin small letter u with circumflex, - U+00FB ISOlat1 --> -<!ENTITY uuml "ü"> <!-- latin small letter u with diaeresis, - U+00FC ISOlat1 --> -<!ENTITY yacute "ý"> <!-- latin small letter y with acute, - U+00FD ISOlat1 --> -<!ENTITY thorn "þ"> <!-- latin small letter thorn with, - U+00FE ISOlat1 --> -<!ENTITY yuml "ÿ"> <!-- latin small letter y with diaeresis, - U+00FF ISOlat1 --> diff --git a/lib/docbuilder/ebin/.gitignore b/lib/docbuilder/ebin/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/docbuilder/ebin/.gitignore +++ /dev/null diff --git a/lib/docbuilder/etc/Makefile b/lib/docbuilder/etc/Makefile deleted file mode 100644 index a2f669d749..0000000000 --- a/lib/docbuilder/etc/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -# ``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 -# ---------------------------------------------------- - -VAR_FILES = \ - note.gif \ - warning.gif - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: - -clean: - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: - $(INSTALL_DIR) $(RELSYSDIR)/etc - $(INSTALL_DATA) $(VAR_FILES) $(RELSYSDIR)/etc - -release_docs_spec: - - - - - - - diff --git a/lib/docbuilder/etc/note.gif b/lib/docbuilder/etc/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/lib/docbuilder/etc/note.gif +++ /dev/null diff --git a/lib/docbuilder/etc/warning.gif b/lib/docbuilder/etc/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/lib/docbuilder/etc/warning.gif +++ /dev/null diff --git a/lib/docbuilder/info b/lib/docbuilder/info deleted file mode 100644 index 60daa212c8..0000000000 --- a/lib/docbuilder/info +++ /dev/null @@ -1,2 +0,0 @@ -group: doc -short: Tool for generating HTML documentation for applications. diff --git a/lib/docbuilder/src/Makefile b/lib/docbuilder/src/Makefile deleted file mode 100644 index e8a07a54e8..0000000000 --- a/lib/docbuilder/src/Makefile +++ /dev/null @@ -1,121 +0,0 @@ -# ``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_gen.erl b/lib/docbuilder/src/docb_gen.erl deleted file mode 100644 index 75494314f1..0000000000 --- a/lib/docbuilder/src/docb_gen.erl +++ /dev/null @@ -1,142 +0,0 @@ -%% ``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]). --deprecated([{module,1,next_major_release}, - {module,2,next_major_release}, - {users_guide,1,next_major_release}, - {users_guide,2,next_major_release}]). - --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 deleted file mode 100644 index bdfc5ea876..0000000000 --- a/lib/docbuilder/src/docb_html.erl +++ /dev/null @@ -1,393 +0,0 @@ -%% ``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:keyfind(ID, 1, TermList) of - false -> - {{drop, ["<em><strong>", ID, - "</strong></em> "]}, - Opts}; - {ID, Name, _Description, _Resp} -> - {{drop, ["<em><strong>", Name, - "</strong></em> "]}, - Opts}; - {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:keyfind(ID, 1, TermList) of - false -> - {{drop, ["<a href=\"", PartApplication, - "_term.html#", ID, "\">", ID, - "</a> "]}, Opts}; - {ID, Name, _Description, _Resp} -> - {{drop, ["<a href=\"", PartApplication, - "_term.html#", ID, "\">", Name, - "</a> "]}, Opts}; - {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:keyfind(ID, 1, CiteList) of - false -> - {{drop, - ["<em><strong>", ID, "</strong></em> "]}, - Opts}; - {ID, Name, _Description, _Resp} -> - {{drop, ["<em><strong>", Name, - "</strong></em> "]}, - Opts}; - {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:keyfind(ID, 1, CiteList) of - false -> - {{drop, ["<a href=\"", PartApp, - "_cite.html#", ID, "\">", ID, - "</a> "]}, - Opts}; - {ID, Name, _Description, _Resp} -> - {{drop, ["<a href=\"", PartApp, - "_cite.html#", ID, "\">", Name, - "</a> "]}, - Opts}; - {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 deleted file mode 100644 index dca80ac58e..0000000000 --- a/lib/docbuilder/src/docb_html_layout.erl +++ /dev/null @@ -1,380 +0,0 @@ -%% ``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 deleted file mode 100644 index c5c166f1ae..0000000000 --- a/lib/docbuilder/src/docb_html_ref.erl +++ /dev/null @@ -1,79 +0,0 @@ -%% ``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 deleted file mode 100644 index 02ce8b52a7..0000000000 --- a/lib/docbuilder/src/docb_html_util.erl +++ /dev/null @@ -1,542 +0,0 @@ -%% ``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("&") -> "&"; -entity_to_html("\"") -> """; -entity_to_html("<") -> "<"; -entity_to_html(">") -> ">"; -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:keyfind(Key, 1, List) of - {Key, [], []} -> - ""; - {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) -> - [format_toc1(T) || T <- Toc]. - -format_toc1({Number, Title}) -> - [Number, " <a href = \"#", Number, "\">", Title, "</a><br/>\n"]. - -%%--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 deleted file mode 100644 index c836805cd2..0000000000 --- a/lib/docbuilder/src/docb_html_util_iso.erl +++ /dev/null @@ -1,204 +0,0 @@ -%% ``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 ]") -> "D"; -%% enc("[Dot ]") -> "�"; -%% enc("[DotDot]") -> "�"; -enc("[Gamma ]") -> "G"; -enc("[Lambda]") -> "L"; -enc("[Omega ]") -> "W"; -enc("[Phi ]") -> "F"; -enc("[Pi ]") -> "P"; -enc("[Prime ]") -> "²"; -enc("[Psi ]") -> "Y"; -enc("[Sigma ]") -> "S"; -enc("[Theta ]") -> "Q"; -enc("[Upsi ]") -> "¡"; -%% enc("[Verbar]") -> "�"; -enc("[Xi ]") -> "X"; - -enc("[aleph ]") -> "À"; -enc("[alpha ]") -> "a"; -enc("[amp ]") -> "&"; -enc("[and ]") -> "Ù"; -enc("[ang ]") -> "Ð"; -%% enc("[ang90 ]") -> "�"; -%% enc("[angsph]") -> "�"; -%% enc("[angst ]") -> "�"; -enc("[ap ]") -> "»"; - -%% enc("[becaus]") -> "�"; -%% enc("[bernou]") -> "�"; -enc("[bepsi ]") -> "'"; -enc("[beta ]") -> "b"; -enc("[bottom]") -> "^"; -enc("[bull ]") -> "·"; - -enc("[cap ]") -> "Ç"; -enc("[chi ]") -> "c"; -enc("[clubs ]") -> "§"; -%% enc("[compfn]") -> "�"; -enc("[cong ]") -> "@"; -enc("[copy ]") -> "Ó"; -%% enc("[conint]") -> "�"; -enc("[cup ]") -> "È"; - -enc("[dArr ]") -> "ß"; -enc("[darr ]") -> "¯"; -enc("[deg ]") -> "°"; -enc("[delta ]") -> "d"; -enc("[diam ]") -> "à"; -enc("[diams ]") -> "¨"; -enc("[divide]") -> "¸"; - -enc("[empty ]") -> "Æ"; -%% enc("[epsi ]") -> "�"; -%% enc("[epsis ]") -> "�"; -enc("[epsiv ]") -> "e"; -enc("[equiv ]") -> "º"; -enc("[eta ]") -> "h"; -enc("[exist ]") -> "$"; - -enc("[fnof ]") -> "¦"; -enc("[forall]") -> """; - -enc("[gamma ]") -> "g"; -%% enc("[gammad]") -> "�"; -enc("[ge ]") -> "³"; -enc("[gt ]") -> ">"; - -%% enc("[hamilt]") -> "�"; -enc("[hArr ]") -> "Û"; -enc("[harr ]") -> "«"; -enc("[hearts]") -> "©"; -enc("[horbar]") -> "¾"; - -enc("[iff ]") -> "Û"; -enc("[image ]") -> "Á"; -enc("[infin ]") -> "¥"; -enc("[int ]") -> "ò"; -enc("[iota ]") -> "i"; -enc("[isin ]") -> "Î"; - -enc("[kappa ]") -> "k"; -%%enc("[kappav]") -> "�"; - -enc("[lArr ]") -> "Ü"; -%% enc("[lagran]") -> "�"; -enc("[lambda]") -> "l"; -enc("[lang ]") -> "á"; -enc("[larr ]") -> "¬"; -enc("[le ]") -> "£"; -%% enc("[lowast]") -> "�"; -enc("[lowbar]") -> "_"; -enc("[lt ]") -> "<"; - -enc("[middot]") -> "×"; -enc("[minus ]") -> "-"; -%% enc("[mnplus]") -> "�"; -enc("[mu ]") -> "m"; - -enc("[nabla ]") -> "Ñ"; -enc("[ne ]") -> "¹"; -enc("[ni ]") -> "'"; -enc("[nsub ]") -> "Ë"; -enc("[not ]") -> "Ø"; -enc("[notin ]") -> "Ï"; -enc("[nu ]") -> "n"; - -enc("[omega ]") -> "w"; -enc("[or ]") -> "Ú"; -%% enc("[order ]") -> "�"; -enc("[oplus ]") -> "Å"; -enc("[otimes]") -> "Ä"; - -%% enc("[par ]") -> "�"; -enc("[part ]") -> "¶"; -%% enc("[permil]") -> "�"; -enc("[perp ]") -> "^"; % bottom -enc("[phis ]") -> "f"; -enc("[phiv ]") -> "j"; -%% enc("[phmmat]") -> "�"; -enc("[pi ]") -> "p"; -enc("[piv ]") -> "v"; -enc("[plus ]") -> "+"; -enc("[plusmn]") -> "±"; -enc("[prime ]") -> "¢"; -enc("[prod ]") -> "Õ"; -enc("[prop ]") -> "µ"; -enc("[psi ]") -> "y"; - -enc("[radic ]") -> "Ö"; -enc("[rang ]") -> "ñ"; -enc("[rArr ]") -> "Þ"; -enc("[rarr ]") -> "®"; -enc("[real ]") -> "Â"; -enc("[reg ]") -> "Ò"; -enc("[rho ]") -> "r"; -%% enc("[rhov ]") -> "�"; - -enc("[sigma ]") -> "s"; -enc("[sigmav]") -> "V"; -enc("[sim ]") -> "~"; -%% enc("[sime ]") -> "�"; -%% enc("[square]") -> "�"; -enc("[sol ]") -> "¤"; -enc("[spades]") -> "ª"; -enc("[sub ]") -> "Ì"; -enc("[sube ]") -> "Í"; -enc("[sup ]") -> "É"; -enc("[supe ]") -> "Ê"; -enc("[sum ]") -> "å"; - -enc("[tau ]") -> "t"; -enc("[tdot ]") -> "¼"; -enc("[there4]") -> "\"; -enc("[thetas]") -> "q"; -enc("[thetav]") -> "J"; -enc("[times ]") -> "´"; -%% enc("[tprime]") -> "�"; -enc("[trade ]") -> "Ô"; - -enc("[uArr ]") -> "Ý"; -enc("[uarr ]") -> "­"; -enc("[upsi ]") -> "u"; - -enc("[verbar]") -> "½"; - -%% enc("[wedgeq]") -> "�"; -enc("[weierp]") -> "Ã"; - -enc("[xi ]") -> "x"; - -enc("[zeta ]") -> "z". diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl deleted file mode 100644 index c20cfc8e67..0000000000 --- a/lib/docbuilder/src/docb_main.erl +++ /dev/null @@ -1,657 +0,0 @@ -%% ``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) -> - - SrcType = docb_util:lookup_option(src_type, Opts), - - File1 = - case SrcType of - ".xml" -> - FileTmp = 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 > " ++ FileTmp ++ ".xml"), - FileTmp; - ".sgml" -> - File - end, - - case parse1(File1, Opts) of - errors -> - delete_tmp_file(SrcType, File1), - 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 -> - delete_tmp_file(SrcType, File1), - errors; - _ -> - delete_tmp_file(SrcType, File1), - ok - end - - end. - - -delete_tmp_file(".xml", File) -> - file:delete(File ++ ".xml"); -delete_tmp_file(_, _) -> - ok. - -%%---------------------------------------------------------------------- - -%% 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) -> - verify_optional(Optional, Path, Level) - andalso verify_list(Args, [Tag|Path], Level); -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) -> - verify(H, Path, Level) andalso verify_list(T, Path, Level + 1); -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 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 Filter:extension(NewOpts) of - {'EXIT', _} -> - 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 -> - 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 deleted file mode 100644 index 25dcd8987b..0000000000 --- a/lib/docbuilder/src/docb_pretty_format.erl +++ /dev/null @@ -1,177 +0,0 @@ -%% ``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 is_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 is_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 deleted file mode 100644 index d8cb214d0a..0000000000 --- a/lib/docbuilder/src/docb_tr_application2html.erl +++ /dev/null @@ -1,286 +0,0 @@ -%% ``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:keyfind(File, 1, FascData) of - {_, _, "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}], - 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]) -> - 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) -> - [element(3, Tuple) || Tuple <- 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 deleted file mode 100644 index 6b4cc0f815..0000000000 --- a/lib/docbuilder/src/docb_tr_appref2html.erl +++ /dev/null @@ -1,48 +0,0 @@ -%% ``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 deleted file mode 100644 index 185cdc7cc3..0000000000 --- a/lib/docbuilder/src/docb_tr_chapter2html.erl +++ /dev/null @@ -1,59 +0,0 @@ -%% ``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 deleted file mode 100644 index 77f1c4e636..0000000000 --- a/lib/docbuilder/src/docb_tr_cite2html.erl +++ /dev/null @@ -1,134 +0,0 @@ -%% ``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:keyfind(ID, 1, CiteList) of - false -> - [{cite, [{"NAME","CDATA",ID}, {"ID","CDATA",ID}], More}| - purge_body(Rest, CiteList)]; - {ID, Name, _Description, _Responsible} -> - [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}| - purge_body(Rest, CiteList)]; - {ID, Name, _Description} -> - [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}| - purge_body(Rest, CiteList)] - end; -purge_body([{_Tag,_Attrs,More}|Rest], CiteList) -> - 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:keyfind(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}; - {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}; - {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:keyfind(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}; - {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}; - {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 deleted file mode 100644 index 25207dccb4..0000000000 --- a/lib/docbuilder/src/docb_tr_comref2html.erl +++ /dev/null @@ -1,46 +0,0 @@ -%% ``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 deleted file mode 100644 index 06748b8c57..0000000000 --- a/lib/docbuilder/src/docb_tr_cref2html.erl +++ /dev/null @@ -1,61 +0,0 @@ -%% ``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 deleted file mode 100644 index b264c46bce..0000000000 --- a/lib/docbuilder/src/docb_tr_erlref2html.erl +++ /dev/null @@ -1,46 +0,0 @@ -%% ``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 deleted file mode 100644 index 60280543a8..0000000000 --- a/lib/docbuilder/src/docb_tr_fileref2html.erl +++ /dev/null @@ -1,46 +0,0 @@ -%% ``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 deleted file mode 100644 index e9ecbe73cb..0000000000 --- a/lib/docbuilder/src/docb_tr_first2html.erl +++ /dev/null @@ -1,46 +0,0 @@ -%% ``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 deleted file mode 100644 index 312342add2..0000000000 --- a/lib/docbuilder/src/docb_tr_index2html.erl +++ /dev/null @@ -1,195 +0,0 @@ -%% ``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) -> - [T || T = {pcdata, _, _} <- 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 deleted file mode 100644 index 30befe8432..0000000000 --- a/lib/docbuilder/src/docb_tr_part2html.erl +++ /dev/null @@ -1,237 +0,0 @@ -%% ``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:keyfind(File, 1, FascData) of - {_, _, "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, - {title,_,Title} = lists:keyfind(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, - 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) -> - [element(3, Tuple) || Tuple <- 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 deleted file mode 100644 index dc60c329fc..0000000000 --- a/lib/docbuilder/src/docb_tr_refs2kwic.erl +++ /dev/null @@ -1,156 +0,0 @@ -%% ``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 deleted file mode 100644 index 3386ed972a..0000000000 --- a/lib/docbuilder/src/docb_tr_report2html.erl +++ /dev/null @@ -1,70 +0,0 @@ -%% ``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 deleted file mode 100644 index a3c4a5312a..0000000000 --- a/lib/docbuilder/src/docb_tr_term2html.erl +++ /dev/null @@ -1,124 +0,0 @@ -%% ``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:keyfind(ID, 1, TermList) of - false -> - [{term,[{"NAME","CDATA",ID},{"ID","CDATA",ID}],More}| - purge_body(Rest, TermList)]; - {ID, Name, _Description, _Responsible} -> - [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}| - purge_body(Rest, TermList)]; - {ID, Name, _Description} -> - [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}| - purge_body(Rest, TermList)] - end; -purge_body([{_Tag,_Attrs,More}|Rest], TermList) -> - 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:keyfind(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}; - {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}; - {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:keyfind(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}; - {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}; - {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 deleted file mode 100644 index 736ac92274..0000000000 --- a/lib/docbuilder/src/docb_transform.erl +++ /dev/null @@ -1,163 +0,0 @@ -%% ``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]). --deprecated([{file,1,next_major_release}, - {file,2,next_major_release}]). - -%% 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:keyfind(Key, 1, Opts) of - {_, 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 deleted file mode 100644 index 9b2eec7733..0000000000 --- a/lib/docbuilder/src/docb_util.erl +++ /dev/null @@ -1,237 +0,0 @@ -%% ``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 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 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:keyfind(Opt, 1, Opts) of - {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 deleted file mode 100644 index 01ef3f7fca..0000000000 --- a/lib/docbuilder/src/docb_util.hrl +++ /dev/null @@ -1,34 +0,0 @@ -%% ``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 deleted file mode 100644 index bc62069230..0000000000 --- a/lib/docbuilder/src/docb_xmerl_tree_cb.erl +++ /dev/null @@ -1,343 +0,0 @@ -%% ``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! -%% <some result> -%% </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:keyfind(NameA, #xmlAttribute.name, GivenAttrs) of - #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/docbuilder.app.src b/lib/docbuilder/src/docbuilder.app.src deleted file mode 100644 index 64c4770964..0000000000 --- a/lib/docbuilder/src/docbuilder.app.src +++ /dev/null @@ -1,37 +0,0 @@ -{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 deleted file mode 100644 index 54a63833e6..0000000000 --- a/lib/docbuilder/src/docbuilder.appup.src +++ /dev/null @@ -1 +0,0 @@ -{"%VSN%",[],[]}. diff --git a/lib/docbuilder/test/Makefile b/lib/docbuilder/test/Makefile deleted file mode 100644 index 53dff193dc..0000000000 --- a/lib/docbuilder/test/Makefile +++ /dev/null @@ -1,80 +0,0 @@ -# ``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 express 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, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -MODULES = \ - docb_SUITE - -ERL_FILES= $(MODULES:%=%.erl) - -TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -INSTALL_PROGS= $(TARGET_FILES) - -EMAKEFILE=Emakefile - -SPEC_FILES= - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/docb_test - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_MAKE_FLAGS += -ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include - -EBIN = . - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- -.PHONY: make_emakefile - -make_emakefile: - $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ - > $(EMAKEFILE) - -tests debug opt: make_emakefile - erl $(ERL_MAKE_FLAGS) -make - -clean: - rm -f $(EMAKEFILE) - rm -f $(TARGET_FILES) - rm -f core - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - -release_tests_spec: make_emakefile - $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(SPEC_FILES) docb.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) - chmod -R u+w $(RELSYSDIR) - @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) - -release_docs_spec: - - diff --git a/lib/docbuilder/test/docb.cover b/lib/docbuilder/test/docb.cover deleted file mode 100644 index 80bab6eba7..0000000000 --- a/lib/docbuilder/test/docb.cover +++ /dev/null @@ -1,2 +0,0 @@ -{incl_app,docbuilder,details} - diff --git a/lib/docbuilder/test/docb_SUITE.erl b/lib/docbuilder/test/docb_SUITE.erl deleted file mode 100644 index d286824539..0000000000 --- a/lib/docbuilder/test/docb_SUITE.erl +++ /dev/null @@ -1,50 +0,0 @@ -%% ``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 express 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, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id$ -%% --module(docb_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,html/1]). - --include_lib("common_test/include/ct.hrl"). - --include_lib("kernel/include/file.hrl"). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> -[html]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -html(suite) -> []; -html(Config) when is_list(Config) -> - ok. - diff --git a/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml b/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml deleted file mode 100755 index b7f6f5376e..0000000000 --- a/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> -<chapter> - <header> - <title>�Docbookö bug</title> - <prepared>Matthias Lang</prepared> -<docno></docno> -<date>2008-03-31</date> - <rev>1.0</rev> - </header> - -<section><title>This is a title</title> - <code><![CDATA[ - This works - ]]></code> - - <code><![CDATA[ - This does not - ]]> </code> -</section> -</chapter> - diff --git a/lib/docbuilder/vsn.mk b/lib/docbuilder/vsn.mk deleted file mode 100644 index 6df438a537..0000000000 --- a/lib/docbuilder/vsn.mk +++ /dev/null @@ -1 +0,0 @@ -DOCB_VSN = 0.9.8.11 diff --git a/lib/docbuilder/xsd/application.xsd b/lib/docbuilder/xsd/application.xsd deleted file mode 100755 index eb666cb6c7..0000000000 --- a/lib/docbuilder/xsd/application.xsd +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="application">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/appref.xsd b/lib/docbuilder/xsd/appref.xsd deleted file mode 100755 index b63839e494..0000000000 --- a/lib/docbuilder/xsd/appref.xsd +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <!-- Structure -->
- <xs:element name="appref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="app"/>
- <xs:element ref="appsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="app" type="xs:string"/>
- <xs:element name="appsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/book.xsd b/lib/docbuilder/xsd/book.xsd deleted file mode 100755 index b47962263a..0000000000 --- a/lib/docbuilder/xsd/book.xsd +++ /dev/null @@ -1,292 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.table.xsd"/>
- <xs:element name="book">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="insidecover"/>
- <xs:element ref="pagetext"/>
- <xs:element ref="preamble"/>
- <xs:choice maxOccurs="unbounded">
- <xs:element ref="applications"/>
- <xs:element ref="parts"/>
- <xs:element ref="headline"/>
- <xs:element ref="pagetext"/>
- </xs:choice>
- <xs:sequence>
- <xs:element minOccurs="0" ref="listoffigures"/>
- <xs:element minOccurs="0" ref="listoftables"/>
- <xs:element minOccurs="0" ref="listofterms"/>
- <xs:element minOccurs="0" ref="bibliography"/>
- <xs:element minOccurs="0" ref="index"/>
- </xs:sequence>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="header">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="title"/>
- <xs:element ref="prepared"/>
- <xs:element minOccurs="0" ref="responsible"/>
- <xs:element ref="docno"/>
- <xs:element minOccurs="0" ref="approved"/>
- <xs:element minOccurs="0" ref="checked"/>
- <xs:element ref="date"/>
- <xs:element ref="rev"/>
- <xs:element minOccurs="0" ref="file"/>
- <xs:element minOccurs="0" ref="abbreviation"/>
- </xs:sequence>
- <xs:attribute name="titlestyle" default="normal">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="special"/>
- <xs:enumeration value="normal"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="title">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="prepared">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="responsible">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="docno">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="approved">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="checked">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="date">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="rev">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="file">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="abbreviation">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="pagetext" type="xs:string"/>
- <xs:element name="preamble">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="preface"/>
- <xs:element minOccurs="0" ref="contents"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="preface">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="table"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="insidecover">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- <xs:element ref="tt"/>
- <xs:element ref="bold"/>
- <xs:element ref="include"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="tt">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="bold">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="vfill">
- <xs:complexType/>
- </xs:element>
- <xs:element name="theheader">
- <xs:complexType>
- <xs:attribute name="tag" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="title"/>
- <xs:enumeration value="prepared"/>
- <xs:enumeration value="responsible"/>
- <xs:enumeration value="docno"/>
- <xs:enumeration value="approved"/>
- <xs:enumeration value="checked"/>
- <xs:enumeration value="date"/>
- <xs:enumeration value="rev"/>
- <xs:enumeration value="file"/>
- <xs:enumeration value="abbreviation"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="applications">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="parts">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="include"/>
- <xs:element ref="onepart"/>
- </xs:choice>
- </xs:sequence>
- <xs:attribute name="lift" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="headline" type="xs:string"/>
- <xs:element name="index">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listoffigures">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listoftables">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listofterms">
- <xs:complexType/>
- </xs:element>
- <xs:element name="bibliography">
- <xs:complexType/>
- </xs:element>
- <xs:element name="contents">
- <xs:complexType>
- <xs:attribute name="level" default="2">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="0"/>
- <xs:enumeration value="1"/>
- <xs:enumeration value="2"/>
- <xs:enumeration value="3"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="onepart">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- <xs:attribute name="lift" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/chapter.xsd b/lib/docbuilder/xsd/chapter.xsd deleted file mode 100755 index 4d89baa988..0000000000 --- a/lib/docbuilder/xsd/chapter.xsd +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:include schemaLocation="common.table.xsd"/>
- <xs:include schemaLocation="common.image.xsd"/>
- <!-- Structure -->
- <xs:element name="chapter">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="br"/>
- <xs:element ref="image"/>
- <xs:element ref="marker"/>
- <xs:element ref="table"/>
- </xs:choice>
- <xs:element maxOccurs="unbounded" ref="section"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="section">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="marker"/>
- <xs:element ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="br"/>
- <xs:element ref="image"/>
- <xs:element ref="marker"/>
- <xs:element ref="table"/>
- <xs:element ref="section"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.entities.xsd b/lib/docbuilder/xsd/common.entities.xsd deleted file mode 100755 index 52a5d35179..0000000000 --- a/lib/docbuilder/xsd/common.entities.xsd +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"/>
diff --git a/lib/docbuilder/xsd/common.header.xsd b/lib/docbuilder/xsd/common.header.xsd deleted file mode 100755 index bfee4b8bb4..0000000000 --- a/lib/docbuilder/xsd/common.header.xsd +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="header">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="title"/>
- <xs:element minOccurs="0" ref="shorttitle"/>
- <xs:element ref="prepared"/>
- <xs:element minOccurs="0" ref="responsible"/>
- <xs:element ref="docno"/>
- <xs:element minOccurs="0" ref="approved"/>
- <xs:element minOccurs="0" ref="checked"/>
- <xs:element ref="date"/>
- <xs:element ref="rev"/>
- <xs:element minOccurs="0" ref="file"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="shorttitle" type="xs:string"/>
- <xs:element name="prepared" type="xs:string"/>
- <xs:element name="responsible" type="xs:string"/>
- <xs:element name="docno" type="xs:string"/>
- <xs:element name="approved" type="xs:string"/>
- <xs:element name="checked" type="xs:string"/>
- <xs:element name="date" type="xs:string"/>
- <xs:element name="rev" type="xs:string"/>
- <xs:element name="file" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.image.xsd b/lib/docbuilder/xsd/common.image.xsd deleted file mode 100755 index 17054eb23c..0000000000 --- a/lib/docbuilder/xsd/common.image.xsd +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="image">
- <xs:complexType>
- <xs:complexContent>
- <xs:extension base="icaption">
- <xs:attribute name="file" use="required"/>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
- </xs:element>
- <xs:complexType name="icaption">
- <xs:sequence>
- <xs:element ref="icaption"/>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="icaption" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.refs.xsd b/lib/docbuilder/xsd/common.refs.xsd deleted file mode 100755 index 58b450669d..0000000000 --- a/lib/docbuilder/xsd/common.refs.xsd +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!--
- This file contains common stuff for the *ref.dtd files.
- Note that `name' is defined in each *ref.dtd.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="funcs">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="func"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="func">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="name"/>
- <xs:element ref="fsummary"/>
- <xs:element minOccurs="0" ref="type"/>
- <xs:element minOccurs="0" ref="desc"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- ELEMENT name is defined in each ref dtd -->
- <xs:element name="fsummary">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="type">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="v"/>
- <xs:element minOccurs="0" ref="d"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="v" type="xs:string"/>
- <xs:element name="d">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="desc">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="authors">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="aname"/>
- <xs:element ref="email"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="aname" type="xs:string"/>
- <xs:element name="email" type="xs:string"/>
- <xs:element name="section">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="marker"/>
- <xs:element ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.table.xsd b/lib/docbuilder/xsd/common.table.xsd deleted file mode 100755 index cf63df4317..0000000000 --- a/lib/docbuilder/xsd/common.table.xsd +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="table">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="row"/>
- <xs:element ref="tcaption"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="row">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="cell"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="cell">
- <xs:complexType mixed="true">
- <xs:group minOccurs="0" maxOccurs="unbounded" ref="inline"/>
- <xs:attribute name="align" default="left">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="left"/>
- <xs:enumeration value="center"/>
- <xs:enumeration value="right"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="valign" default="middle">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="top"/>
- <xs:enumeration value="middle"/>
- <xs:enumeration value="bottom"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="tcaption" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.xsd b/lib/docbuilder/xsd/common.xsd deleted file mode 100755 index 3d43390bd8..0000000000 --- a/lib/docbuilder/xsd/common.xsd +++ /dev/null @@ -1,212 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!-- This file contains common stuff for all dtds. -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="block" abstract="true"/>
- <xs:group name="inline">
- <xs:sequence>
- <xs:choice minOccurs="0">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- <xs:element ref="term"/>
- <xs:element ref="cite"/>
- <xs:element ref="br"/>
- <xs:element ref="path"/>
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:sequence>
- </xs:group>
- <!-- XXX -->
- <xs:element name="p" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:group minOccurs="0" maxOccurs="unbounded" ref="inline"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="pre" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- <xs:element ref="input"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="input">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="code" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:attribute name="type" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="erl"/>
- <xs:enumeration value="c"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="quote">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="p"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="warning">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="note">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="c" type="xs:string"/>
- <xs:element name="em">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="c"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- XXX -->
- <xs:element name="term">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="termdef"/>
- </xs:sequence>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="termdef" type="xs:string"/>
- <xs:element name="cite">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="citedef"/>
- </xs:sequence>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="citedef">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="ctitle"/>
- <xs:element ref="cauthor"/>
- <xs:element ref="chowpublished"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="ctitle" type="xs:string"/>
- <xs:element name="cauthor" type="xs:string"/>
- <xs:element name="chowpublished" type="xs:string"/>
- <!-- XXX -->
- <xs:element name="br">
- <xs:complexType/>
- </xs:element>
- <!-- Path -->
- <xs:element name="path">
- <xs:complexType mixed="true">
- <xs:attribute name="unix" default=""/>
- <xs:attribute name="windows" default=""/>
- </xs:complexType>
- </xs:element>
- <!-- List -->
- <xs:element name="list" substitutionGroup="block">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="item"/>
- </xs:sequence>
- <xs:attribute name="type" default="bulleted">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="ordered"/>
- <xs:enumeration value="bulleted"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="taglist" substitutionGroup="block">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="tag"/>
- <xs:element ref="item"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="tag">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="item">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:group ref="inline"/>
- <xs:element ref="block"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <!-- References -->
- <xs:element name="seealso">
- <xs:complexType mixed="true">
- <xs:attribute name="marker" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="url">
- <xs:complexType mixed="true">
- <xs:attribute name="href" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="marker">
- <xs:complexType>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <!-- CodeInclude -->
- <xs:element name="codeinclude" substitutionGroup="block">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- <xs:attribute name="tag" default=""/>
- <xs:attribute name="type" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="erl"/>
- <xs:enumeration value="c"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <!-- ErlEval -->
- <xs:element name="erleval" substitutionGroup="block">
- <xs:complexType>
- <xs:attribute name="expr" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/comref.xsd b/lib/docbuilder/xsd/comref.xsd deleted file mode 100755 index 61df4dd848..0000000000 --- a/lib/docbuilder/xsd/comref.xsd +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="comref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="com"/>
- <xs:element ref="comsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="com" type="xs:string"/>
- <xs:element name="comsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/cref.xsd b/lib/docbuilder/xsd/cref.xsd deleted file mode 100755 index f1cbeddfff..0000000000 --- a/lib/docbuilder/xsd/cref.xsd +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="cref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="lib"/>
- <xs:element ref="libsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="lib" type="xs:string"/>
- <xs:element name="libsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="ret"/>
- <xs:element ref="nametext"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="ret" type="xs:string"/>
- <xs:element name="nametext" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/erlref.xsd b/lib/docbuilder/xsd/erlref.xsd deleted file mode 100755 index f6011b7bea..0000000000 --- a/lib/docbuilder/xsd/erlref.xsd +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="erlref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="module"/>
- <xs:element ref="modulesummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="module" type="xs:string"/>
- <xs:element name="modulesummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/fascicules.xsd b/lib/docbuilder/xsd/fascicules.xsd deleted file mode 100755 index bfdb5bd604..0000000000 --- a/lib/docbuilder/xsd/fascicules.xsd +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<!-- Structure -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="fascicules">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="fascicule"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="fascicule">
- <xs:complexType mixed="true">
- <xs:attribute name="file" use="required"/>
- <xs:attribute name="href" use="required"/>
- <xs:attribute name="entry" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/fileref.xsd b/lib/docbuilder/xsd/fileref.xsd deleted file mode 100755 index 8038f2115f..0000000000 --- a/lib/docbuilder/xsd/fileref.xsd +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="fileref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="file"/>
- <xs:element ref="filesummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- Note: ELEMENT file is already defined -->
- <xs:element name="filesummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/part.xsd b/lib/docbuilder/xsd/part.xsd deleted file mode 100755 index 30d6ec0120..0000000000 --- a/lib/docbuilder/xsd/part.xsd +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="part">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/edoc/doc/Makefile b/lib/edoc/doc/Makefile index c5f68b25d0..7a59809d9b 100644 --- a/lib/edoc/doc/Makefile +++ b/lib/edoc/doc/Makefile @@ -78,12 +78,3 @@ release_docs_spec: docs release_spec: - - - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- -#-include make.dep - - diff --git a/lib/edoc/doc/src/make.dep b/lib/edoc/doc/src/make.dep deleted file mode 100644 index b46e36314f..0000000000 --- a/lib/edoc/doc/src/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex chapter.tex edoc.tex edoc_doclet.tex \ - edoc_extract.tex edoc_layout.tex edoc_lib.tex \ - edoc_run.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/erl_docgen/Makefile b/lib/erl_docgen/Makefile index 93a6353cac..68b41a1ff2 100644 --- a/lib/erl_docgen/Makefile +++ b/lib/erl_docgen/Makefile @@ -23,8 +23,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # -SUB_DIRECTORIES = src priv -#doc/src +SUB_DIRECTORIES = src priv doc/src include vsn.mk VSN = $(ERL_DOCGEN_VSN) diff --git a/lib/docbuilder/doc/html/.gitignore b/lib/erl_docgen/doc/html/.gitignore index e69de29bb2..e69de29bb2 100644 --- a/lib/docbuilder/doc/html/.gitignore +++ b/lib/erl_docgen/doc/html/.gitignore diff --git a/lib/docbuilder/doc/man3/.gitignore b/lib/erl_docgen/doc/man6/.gitignore index e69de29bb2..e69de29bb2 100644 --- a/lib/docbuilder/doc/man3/.gitignore +++ b/lib/erl_docgen/doc/man6/.gitignore diff --git a/lib/docbuilder/doc/man6/.gitignore b/lib/erl_docgen/doc/pdf/.gitignore index e69de29bb2..e69de29bb2 100644 --- a/lib/docbuilder/doc/man6/.gitignore +++ b/lib/erl_docgen/doc/pdf/.gitignore diff --git a/lib/docbuilder/doc/src/Makefile b/lib/erl_docgen/doc/src/Makefile index ae34266844..a546d8da33 100644 --- a/lib/docbuilder/doc/src/Makefile +++ b/lib/erl_docgen/doc/src/Makefile @@ -1,21 +1,22 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2011-2011. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # 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 online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # +# include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -23,8 +24,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Application version # ---------------------------------------------------- include ../../vsn.mk -VSN=$(DOCB_VSN) -APPLICATION=docbuilder +VSN=$(ERL_DOCGEN_VSN) +APPLICATION=erl_docgen # ---------------------------------------------------- # Release directory specification @@ -35,45 +36,43 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = ref_man.xml -XML_REF3_FILES = \ - docb_gen.xml \ - docb_transform.xml \ - docb_xml_check.xml XML_REF6_FILES = \ - docbuilder_app.xml + erl_docgen_app.xml + +XML_PART_FILES = \ + part.xml -XML_PART_FILES = part.xml part_notes.xml XML_CHAPTER_FILES = \ overview.xml \ user_guide_dtds.xml \ refman_dtds.xml \ - fasc_dtds.xml \ - header_tags.xml \ - block_tags.xml \ + notes.xml \ inline_tags.xml \ + header_tags.xml \ character_entities.xml \ - notes.xml + block_tags.xml BOOK_FILES = book.xml -GIF_FILES = \ - man.gif +XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF6_FILES) \ + $(XML_PART_FILES) $(XML_CHAPTER_FILES) + +TECHNICAL_DESCR_FILES = +EXAMPLE_FILES = \ + example.txt -XML_FILES = \ - $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES) \ - $(XML_APPLICATION_FILES) +GIF_FILES = \ + man.gif # ---------------------------------------------------- -HTML_FILES = \ - $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) INFO_FILE = ../../info -MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6) HTML_REF_MAN_FILE = $(HTMLDIR)/index.html @@ -83,34 +82,40 @@ TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- +XML_FLAGS += DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +docs: pdf html man + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -docs: pdf html man +$(HTMLDIR)/example.txt: example.txt + $(INSTALL_DATA) $< $@ $(TOP_PDF_FILE): $(XML_FILES) pdf: $(TOP_PDF_FILE) -html: gifs $(HTML_REF_MAN_FILE) - -man: $(MAN3_FILES) $(MAN6_FILES) - -gifs: $(GIF_FILES:%=$(HTMLDIR)/%) - -debug opt: +html: gifs examples $(HTML_REF_MAN_FILE) clean clean_docs: rm -rf $(HTMLDIR)/* - rm -f $(MAN3DIR)/* rm -f $(MAN6DIR)/* rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) - rm -f errs core *~ + rm -f errs core *~ + rm -f $(JD_HTML) $(JD_PACK) + +man: $(MAN6_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +examples: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: # ---------------------------------------------------- # Release Target @@ -124,9 +129,7 @@ release_docs_spec: docs $(INSTALL_DATA) $(HTMLDIR)/* \ $(RELSYSDIR)/doc/html $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 $(INSTALL_DIR) $(RELEASE_PATH)/man/man6 - $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6 + $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6 release_spec: diff --git a/lib/docbuilder/doc/src/block_tags.xml b/lib/erl_docgen/doc/src/block_tags.xml index f5ba083f38..0900d7f008 100644 --- a/lib/docbuilder/doc/src/block_tags.xml +++ b/lib/erl_docgen/doc/src/block_tags.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,7 +33,7 @@ as a paragraph or a list.</p> <p>The following subset of block tags are common for all DTDs in - the DocBuilder DTD suite: + the OTP DTD suite: <marker id="block_subset"></marker> <seealso marker="#pTAG"><p></seealso>, <seealso marker="#preTAG"><pre></seealso>, @@ -81,7 +81,7 @@ sum([]) -> </code> <p>There is an attribute <c>type = "erl" | "c" | "none"</c>, but - currently this attribute is ignored by DocBuilder. Default value + currently this attribute is ignored. Default value is <c>"none"</c></p> <note> @@ -99,18 +99,18 @@ sum([]) -> gives the file name and <c>tag</c> defines a string which delimits the code snippet. Example:</p> <pre> -<codeinclude file="gazonk" tag="%% Erlang example"/> +<codeinclude file="example.txt" tag="%% Erlang example"/> </pre> <p>results in:</p> - <codeinclude file="gazonk" tag="%% Erlang example"/> + <codeinclude file="example.txt" tag="%% Erlang example"/> - <p>provided there is a file named <c>gazonk</c> looking like this: + <p>provided there is a file named <c>examples.txt</c> looking like this: </p> <code> ... %% Erlang example --module(gazonk). +-module(example). start() -> {error,"Pid required!"}. @@ -125,7 +125,7 @@ start(Pid) -> included.</p> <p>There is also an attribute <c>type = "erl" | "c" | "none"</c>, but - currently this attribute is ignored by DocBuilder. Default value + currently this attribute is ignored. Default value is <c>"none"</c></p> </section> diff --git a/lib/erl_docgen/doc/src/book.xml b/lib/erl_docgen/doc/src/book.xml index 9df5c39271..73bfb7916d 100644 --- a/lib/erl_docgen/doc/src/book.xml +++ b/lib/erl_docgen/doc/src/book.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE book SYSTEM "book.dtd"> <book xmlns:xi="http://www.w3.org/2001/XInclude"> <header titlestyle="normal"> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,27 +21,26 @@ </legalnotice> - <title>erl_docgen</title> + <title>Erl_Docgen</title> <prepared>Lars Thorsen</prepared> <docno></docno> - <date>2009-11-10</date> - <rev>0.1</rev> + <date>2011-11-10</date> + <rev>0.3</rev> <file>book.xml</file> </header> - <insidecover> - </insidecover> <pagetext>erl_docgen</pagetext> <preamble> <contents level="2"></contents> </preamble> <parts lift="no"> + <xi:include href="part.xml"/> </parts> <applications> + <xi:include href="ref_man.xml"/> </applications> <releasenotes> <xi:include href="notes.xml"/> </releasenotes> - <listofterms></listofterms> <index></index> </book> diff --git a/lib/docbuilder/doc/src/character_entities.xml b/lib/erl_docgen/doc/src/character_entities.xml index 0a4ae17fb5..9f55b68d18 100644 --- a/lib/docbuilder/doc/src/character_entities.xml +++ b/lib/erl_docgen/doc/src/character_entities.xml @@ -32,7 +32,7 @@ <section> <title>Added Latin 1</title> - <p>The DocBuilder DTD suite uses the same character entities as + <p>The OTP DTD suite uses the same character entities as defined in HTML 3.2 (<c>ISO 8879-1986//ENTITIES Added Latin 1//EN//HTML</c>). That is: for an & (ampersand), use the entity: <c>&amp;</c>, for diff --git a/lib/erl_docgen/doc/src/convert.howto b/lib/erl_docgen/doc/src/convert.howto deleted file mode 100644 index 2c72de8c4c..0000000000 --- a/lib/erl_docgen/doc/src/convert.howto +++ /dev/null @@ -1,13 +0,0 @@ - -- add xmlns:xi="http://www.w3.org/2001/XInclude" on top tag - in files whith include directives - -- change <include file="notes"></include> <xi:include href="notes.xml"/> - -- change <image file="a"/> to <image file="a.gif"/> - -- remove chapers directly in the book and put them in the part instead - --change title to just the application name - -- fix codeinclude : xml --> xmlsrc
\ No newline at end of file diff --git a/lib/docbuilder/doc/src/docb_xml_check.xml b/lib/erl_docgen/doc/src/docgen_xml_check.xml index eff4fc4342..58cf069d81 100644 --- a/lib/docbuilder/doc/src/docb_xml_check.xml +++ b/lib/erl_docgen/doc/src/docgen_xml_check.xml @@ -23,16 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>docb_xml_check</title> + <title>docgen_xml_check</title> <prepared></prepared> <docno></docno> <date></date> <rev></rev> </header> - <module>docb_xml_check</module> + <module>docgen_xml_check</module> <modulesummary>Validate XML documentation source code</modulesummary> <description> - <p><c>docb_xml_check</c> contains functions for validating XML + <p><c>docgen_xml_check</c> contains functions for validating XML documentation source code.</p> </description> diff --git a/lib/erl_docgen/doc/src/erl_docgen.txt b/lib/erl_docgen/doc/src/erl_docgen.txt deleted file mode 100644 index 14a4dc8e10..0000000000 --- a/lib/erl_docgen/doc/src/erl_docgen.txt +++ /dev/null @@ -1,6 +0,0 @@ - - - -/home/otptest/bin/otp_wrap_ssh boddington /home/otptest/bin/otp_build_doc -rel r13b02 -view otptest_r13_daily_doc2 -csfile /usr/local/otp/config-specs/r13_dev.cs -insdir /ldisk/daily_build -_ -
\ No newline at end of file diff --git a/lib/erl_docgen/doc/src/erl_docgen_app.xml b/lib/erl_docgen/doc/src/erl_docgen_app.xml new file mode 100644 index 0000000000..25c473bb7e --- /dev/null +++ b/lib/erl_docgen/doc/src/erl_docgen_app.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE appref SYSTEM "appref.dtd"> + +<appref> + <header> + <copyright> + <year>2011</year><year>2011</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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 online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_docgen</title> + <file>erl_docgen_app.xml</file> + </header> + <app>erl_docgen</app> + <appsummary> + The erl_docgen application is used to produce the OTP documentation. + </appsummary> + + <description> + <p> + The application consists of the following parts + <taglist> + <tag>XSL</tag> + <item> + <p> + A number of XSL files that is used to transform the xml files to html, pdf or man pages. + </p> + </item> + <tag>DTDs</tag> + <item> + <p> + The DTDs used for the OTP documentation. + </p> + </item> + <tag>escripts</tag> + <item> + <p> + Some scripts that is used to produce xml files according to OTP DTDs from some different input. + </p> + </item> + <tag>misc</tag> + <item> + <p> + Erlang logo, javascripts and css stylesheets used in the documentation. + </p> + </item> + </taglist> + </p> + </description> + +</appref> diff --git a/lib/docbuilder/doc/src/gazonk b/lib/erl_docgen/doc/src/example.txt index 1cf0b8f7bc..ad86165391 100644 --- a/lib/docbuilder/doc/src/gazonk +++ b/lib/erl_docgen/doc/src/example.txt @@ -1,7 +1,7 @@ This example code is used in block_tags.xml. %% Erlang example --module(gazonk). +-module(example). start() -> {error,"Pid required!"}. diff --git a/lib/docbuilder/doc/src/fasc_dtds.xml b/lib/erl_docgen/doc/src/fasc_dtds.xml index dec8189b55..dec8189b55 100644 --- a/lib/docbuilder/doc/src/fasc_dtds.xml +++ b/lib/erl_docgen/doc/src/fasc_dtds.xml diff --git a/lib/docbuilder/doc/src/fascicules.xml b/lib/erl_docgen/doc/src/fascicules.xml index 1b9d6bc94d..1b9d6bc94d 100644 --- a/lib/docbuilder/doc/src/fascicules.xml +++ b/lib/erl_docgen/doc/src/fascicules.xml diff --git a/lib/docbuilder/doc/src/header_tags.xml b/lib/erl_docgen/doc/src/header_tags.xml index b1456d679a..902bce4f68 100644 --- a/lib/docbuilder/doc/src/header_tags.xml +++ b/lib/erl_docgen/doc/src/header_tags.xml @@ -104,7 +104,7 @@ <section> <title><shorttitle></title> - <p>This optional tag is ignored by DocBuilder. It will likely be + <p>This optional tag is ignored. It will likely be removed in the future.</p> </section> @@ -112,8 +112,7 @@ <marker id="preparedTAG"></marker> <title><prepared></title> - <p>This tag is intended for administrative use and is ignored by - DocBuilder.</p> + <p>This tag is intended for administrative use and is ignored.</p> </section> <section> @@ -121,7 +120,7 @@ <title><responsible></title> <p>This optional tag is intended for administrative use and is - ignored by DocBuilder.</p> + ignored.</p> </section> <section> @@ -141,7 +140,7 @@ <title><approved></title> <p>This optional tag is intended for administrative use and is - ignored by DocBuilder.</p> + ignored.</p> </section> <section> @@ -149,15 +148,14 @@ <title><checked></title> <p>This optional tag is intended for administrative use and is - ignored by DocBuilder.</p> + ignored.</p> </section> <section> <marker id="dateTAG"></marker> <title><date></title> - <p>This tag is intended for administrative use and is ignored by - DocBuilder.</p> + <p>This tag is intended for administrative use and is ignored.</p> </section> <section> @@ -177,7 +175,7 @@ <title><file></title> <p>This optional tag is intended for administrative use and is - ignored by DocBuilder.</p> + ignored.</p> </section> </chapter> diff --git a/lib/docbuilder/doc/src/inline_tags.xml b/lib/erl_docgen/doc/src/inline_tags.xml index 5bcca54c05..9b27da659b 100644 --- a/lib/docbuilder/doc/src/inline_tags.xml +++ b/lib/erl_docgen/doc/src/inline_tags.xml @@ -92,7 +92,7 @@ inline tag.</p> </section> - <section> + <!-- section> <marker id="pathTAG"></marker> <title><path> - Path</title> @@ -115,7 +115,7 @@ in:</p> <p>"Look at the <path unix=".profile" windows="win.ini">start-up file</path> if you intend to alter the initial behavior."</p> - </section> + </section --> <section> <marker id="seealsoTAG"></marker> @@ -150,16 +150,10 @@ <p>Note the use of "#" before the name of the marker. Note also that the filename extension <c>.html</c> is omitted. This is - because the default behavior of DocBuilder is to translate + because the default behavior is to translate <c><![CDATA[<seealso marker="File#Marker">text</seealso>]]></c> to <c><![CDATA[<A HREF="File.html#Marker">text</A>]]></c>.</p> - <p>The default behaviour can be modified by using the callback - module option to <c>docb_transform:file/1,2</c> and defining a - callback function - <seealso marker="docb_transform#Module:seealso-1">Module:seealso/1</seealso>. - This possibility is for example used in OTP to resolve cross - references between applications.</p> </section> <section> @@ -192,28 +186,6 @@ <term id="HTML"><termdef>Hyper-Text Markup Language</termdef></term> ]]></pre> - <p>For a globally defined term, the tag is empty. Example:</p> - <pre><![CDATA[ -<term id="HTML"/> - ]]></pre> - - <p>Global definitions are given to DocBuilder in a file, using the - <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso> - option <c>term_defs</c>. The file should contain a list of tuples, - one for each term definition, on the format - <c>{Id,Name,Definition,Owner}</c>. The <c>Owner</c> part is just - for administration, if there are several people contributing to a - term definition file. Example:</p> - <pre> -[..., - {"HTML", "HTML", "Hyper-Text Markup Language", "Gunilla"}, - ...]. - </pre> - - <p>DocBuilder will collect both local and global definitions in a - glossary, which can be reached from a link in the left frame of - the HTML documentation.</p> - <p>In the generated HTML, it is the term name which will be visible. For locally defined terms, the id and the name are the same. The name has a hypertext link to the definition in the glossary. @@ -237,21 +209,6 @@ <c><termdef></c>, but for a bibliography list rather than a glossary.</p> - <p>A global bibliography list is given to DocBuilder in a file, - using the <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso> - option <c>cite_defs</c>. The file should contain a list of tuples, - one for each cite, on the format - <c>{Id,Title,Info,Owner}</c>. The <c>Owner</c> part is just - for administration, if there are several people contributing to a - bibliography file. Example:</p> - <pre> -[..., - {"erlbook", - "Concurrent Programming in ERLANG","J. Armstrong, R. Virding, C. Wikström, " - "M. Williams, Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X", - "jocke"}, - ...]. - </pre> </section> </chapter> diff --git a/lib/docbuilder/doc/src/man.gif b/lib/erl_docgen/doc/src/man.gif Binary files differindex 8656c7443d..8656c7443d 100644 --- a/lib/docbuilder/doc/src/man.gif +++ b/lib/erl_docgen/doc/src/man.gif diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index 6a0eece56d..9591b363f7 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -21,14 +21,14 @@ </legalnotice> - <title>erl_docgen Release Notes</title> + <title>Erl_Docgen Release Notes</title> <prepared>otp_appnotes</prepared> <docno>nil</docno> <date>nil</date> <rev>nil</rev> <file>notes.xml</file> </header> - <p>This document describes the changes made to the erl_docgen application.</p> + <p>This document describes the changes made to the <em>erl_docgen</em> application.</p> <section><title>Erl_Docgen 0.2.6</title> diff --git a/lib/docbuilder/doc/src/overview.xml b/lib/erl_docgen/doc/src/overview.xml index ca13c5d436..f0f97d8d45 100644 --- a/lib/docbuilder/doc/src/overview.xml +++ b/lib/erl_docgen/doc/src/overview.xml @@ -29,28 +29,6 @@ </header> <section> - <title>Background</title> - - <p>DocBuilder has been used within the OTP project to generate - documentation for Erlang/OTP itself for more than ten years. - It has now been released as a regular Erlang/OTP application.</p> - - <p>The intention with DocBuilder is that it should be as easy to - use and maintain as possible and generate adequate documentation - for OTP's needs. It uses frames, which can probably be regarded as - old-fashioned today. Hopefully, this should be improved in - the future.</p> - - <p>Originally, DocBuilder input was SGML files and external tools - was used for parsing. The internal version used in the OTP - project can generate not only HTML code but also LaTeX (for PDF - and PostScript) and nroff (for UNIX man pages). (Again, using - external tools). Because of this, the parsed source code is - transformed into a tree structure before being transformed again - into the desired format.</p> - </section> - - <section> <title>DTD Suite</title> <p>Input is written as XML according to one of the DTDs and output @@ -94,10 +72,6 @@ the <c>application</c> or <c>part</c> DTD to write other types of documentation for the application.</p> - <p>A special kind of DTD, - <seealso marker="fasc_dtds">fascicules</seealso>, can be used to - specify the different parts of the documentation, and which one - of those should be shown as default.</p> </section> <section> @@ -120,7 +94,7 @@ <section> <title>Basic Tags</title> - <p>All DTDs in the DocBuilder DTD suite share a basic set of tags. + <p>All DTDs in the OTP DTD suite share a basic set of tags. An author can easily switch from one DTD to another and still use the same basic tags. It is furthermore easy to copy pieces of information from one document to another, even though they do not @@ -143,13 +117,13 @@ <p>For readability and simplicity, the examples have been kept as short as possible. For an example of what the generated HTML - will look like, it is recommended to look at the DocBuilder - documentation itself:</p> + will look like, it is recommended to look at the documentation of + an OTP application.</p> <list> - <item>This User's Guide is written using the <c>part</c> and + <item>This User's Guides are written using the <c>part</c> and <c>chapter</c> DTDs.</item> - <item>The Reference Manual is written using + <item>The Reference Manuals are written using the <c>application</c>, <c>appref</c> and <c>erlref</c> DTDs. </item> </list> @@ -162,23 +136,19 @@ <item> <p>Create the relevant XML files.</p> - <p>If there are EDoc comments in a module, the function - <seealso marker="docb_gen#module/1">docb_gen:module/1,2</seealso> + <p>If there are EDoc comments in a module, the escript + <!-- seealso marker="xml_from_edoc">xml_from_edoc</seealso --> + <c>xml_from_edoc</c> can be used to generate an XML file according to the <c>erlref</c> DTD for this module.</p> </item> - <item> + <!-- item> <p>The XML files can be validated using <seealso marker="docb_xml_check#validate/1">docb_xml_check:validate/1</seealso>. </p> - </item> + </item --> - <item> - <p>Generate HTML files by using - <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso>. - </p> - </item> </list> </section> </chapter> diff --git a/lib/docbuilder/doc/src/part.xml b/lib/erl_docgen/doc/src/part.xml index 546c6c612e..4594778a2f 100644 --- a/lib/docbuilder/doc/src/part.xml +++ b/lib/erl_docgen/doc/src/part.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2007</year><year>2009</year> + <year>2011</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -20,21 +20,20 @@ under the License. </legalnotice> - <title>DocBuilder User's Guide</title> + <title>Erl_Docgen User's Guide</title> <prepared></prepared> <docno></docno> <date></date> <rev></rev> </header> <description> - <p><em>Docbuilder</em> provides functionality for generating HTML + <p><em>Erl_Docgen</em> provides functionality for generating HTML/PDF documentation for Erlang modules and Erlang/OTP applications from XML source code and/or EDoc comments in Erlang source code.</p> </description> <xi:include href="overview.xml"/> <xi:include href="user_guide_dtds.xml"/> <xi:include href="refman_dtds.xml"/> - <xi:include href="fasc_dtds.xml"/> <xi:include href="header_tags.xml"/> <xi:include href="block_tags.xml"/> <xi:include href="inline_tags.xml"/> diff --git a/lib/docbuilder/doc/src/ref_man.xml b/lib/erl_docgen/doc/src/ref_man.xml index 7be8ace32f..a2bc1a10a0 100644 --- a/lib/docbuilder/doc/src/ref_man.xml +++ b/lib/erl_docgen/doc/src/ref_man.xml @@ -4,7 +4,7 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2007</year><year>2009</year> + <year>2011</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,20 +21,16 @@ </legalnotice> - <title>DocBuilder Reference Manual</title> - <prepared></prepared> + <title>Erl_Docgen Reference Manual</title> + <prepared>OTP Team</prepared> <docno></docno> - <date></date> - <rev></rev> + <date>2011-11-10</date> + <rev>0.3</rev> + <file>ref_man.xml</file> </header> <description> - <p><em>DocBuilder</em> provides functionality for generating HTML - documentation for Erlang modules and Erlang/OTP applications - from XML source code and/or EDoc comments in Erlang source code.</p> + <p>The <em>erl_docgen</em> supports the OTP documentation build.</p> </description> - <xi:include href="docbuilder_app.xml"/> - <xi:include href="docb_gen.xml"/> - <xi:include href="docb_transform.xml"/> - <xi:include href="docb_xml_check.xml"/> + <xi:include href="erl_docgen_app.xml"/> </application> diff --git a/lib/docbuilder/doc/src/refman_dtds.xml b/lib/erl_docgen/doc/src/refman_dtds.xml index a7beaed708..7b01c57db4 100644 --- a/lib/docbuilder/doc/src/refman_dtds.xml +++ b/lib/erl_docgen/doc/src/refman_dtds.xml @@ -573,8 +573,8 @@ a <c><![CDATA[<nametext>]]></c> (function name and arguments, plain text).</p> - <p>In the case of an <c>erlref</c> DTD, DocBuilder will - automatically try to add a + <p>In the case of an <c>erlref</c> DTD, it will + automatically be added a <seealso marker="inline_tags#markerTAG">marker</seealso>, <c><![CDATA[<marker id="Name/Arity">]]></c> or <c><![CDATA[<marker id="Name">]]></c>, based on the contents of @@ -585,7 +585,7 @@ <name>foo(Arg1, Arg2) -> ok | {error, Reason}</name> ]]></pre> - <p>DocBuilder will create a marker + <p>Then a marker like this will be added <c><![CDATA[<marker id="foo/2">]]></c> before the function definition in the generated HTML. That is, referring to the function using diff --git a/lib/docbuilder/doc/src/user_guide_dtds.xml b/lib/erl_docgen/doc/src/user_guide_dtds.xml index a2db44f830..a2db44f830 100644 --- a/lib/docbuilder/doc/src/user_guide_dtds.xml +++ b/lib/erl_docgen/doc/src/user_guide_dtds.xml diff --git a/lib/erl_docgen/info b/lib/erl_docgen/info new file mode 100644 index 0000000000..4dc2a02bfb --- /dev/null +++ b/lib/erl_docgen/info @@ -0,0 +1,3 @@ +group: doc Documentation Applications +short: A utility used to produce the OTP documentation. + diff --git a/lib/erl_docgen/priv/Makefile b/lib/erl_docgen/priv/Makefile index f50350bef2..18cf7b90dd 100644 --- a/lib/erl_docgen/priv/Makefile +++ b/lib/erl_docgen/priv/Makefile @@ -22,7 +22,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # -SUB_DIRECTORIES = bin css docbuilder_dtd dtd_html_entities dtd_man_entities images js/flipmenu xsl +SUB_DIRECTORIES = bin css dtd dtd_html_entities dtd_man_entities images js/flipmenu xsl SPECIAL_TARGETS = diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript index 982afece7f..156311565c 100644 --- a/lib/erl_docgen/priv/bin/specs_gen.escript +++ b/lib/erl_docgen/priv/bin/specs_gen.escript @@ -19,7 +19,7 @@ %%% <script> [-I<dir>]... [-o<dir>] [-module Module] [File] %%% -%%% Use EDoc and the layout module 'otp_specs' to create an XML file +%%% Use EDoc and the layout module 'docgen_otp_specs' to create an XML file %%% containing Dialyzer types and specifications (-type, -spec). %%% %%% Options: @@ -69,7 +69,7 @@ usage() -> call_edoc(FileSpec, InclFs, Dir) -> ReadOpts = [{includes, InclFs}, {preprocess, true}], ExtractOpts = [{report_missing_type, false}], - LayoutOpts = [{pretty_printer, erl_pp}, {layout, otp_specs}], + LayoutOpts = [{pretty_printer, erl_pp}, {layout, docgen_otp_specs}], File = case FileSpec of {file, File0} -> File0; {module, Module0} -> Module0 diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript index ee79e82c3a..9a96a3c25a 100755 --- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript +++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript @@ -27,7 +27,7 @@ %% Records %%====================================================================== -record(args, {suffix=".xml", - layout=docb_edoc_xml_cb, + layout=docgen_edoc_xml_cb, def=[], includes=[], preprocess=false, @@ -126,7 +126,7 @@ users_guide(File, Args) -> parse(["-xml" |RawOpts], Type, Args) -> parse(RawOpts, Type, Args); % default, no update of record necessary parse(["-sgml" |RawOpts], Type, Args) -> - parse(RawOpts, Type, Args#args{suffix=".sgml", layout=docb_edoc_sgml_cb}); + parse(RawOpts, Type, Args#args{suffix=".sgml", layout=docgen_edoc_sgml_cb}); parse(["-chapter" |RawOpts], _Type, Args) -> parse(RawOpts, chapter, Args); parse(["-def", Key, Val |RawOpts], Type, Args) -> diff --git a/lib/erl_docgen/priv/docbuilder_dtd/application.dtd b/lib/erl_docgen/priv/docbuilder_dtd/application.dtd deleted file mode 100644 index 8a1e8832ec..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/application.dtd +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common SYSTEM "common.dtd" > -%common; -<!ENTITY % common.header SYSTEM "common.header.dtd" > -%common.header; - -<!ELEMENT application (header,description?,include+) > -<!ELEMENT description (%block;|quote|br|marker|warning|note)* > -<!ELEMENT include EMPTY > -<!ATTLIST include file CDATA #REQUIRED> diff --git a/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd deleted file mode 100644 index 70a5ff37af..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common.refs SYSTEM "common.refs.dtd" > -%common.refs; - -<!-- Structure --> - -<!ELEMENT appref (header,app,appsummary,description, - (section|funcs)*,authors?) > -<!ELEMENT app (#PCDATA) > -<!ELEMENT appsummary (#PCDATA) > - -<!-- `name' is used in common.refs.dtd and must therefore - be defined in each *ref. dtd --> -<!ELEMENT name (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/book.dtd b/lib/erl_docgen/priv/docbuilder_dtd/book.dtd deleted file mode 100644 index bb89a6d255..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/book.dtd +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common SYSTEM "common.dtd" > -%common; -<!ENTITY % common.header SYSTEM "common.header.dtd" > -%common.header; -<!ENTITY % common.table SYSTEM "common.table.dtd" > -%common.table; - -<!ELEMENT book (header, - insidecover?, - pagetext, - preamble, - (applications|parts|headline|pagetext)+, - (listoffigures?, - listoftables?, - listofterms?, - bibliography?, - index?)) > - -<!ELEMENT pagetext (#PCDATA) > -<!ELEMENT preamble (contents?,preface?) > -<!ELEMENT preface (title?,(%block;|quote|br|marker|warning|note|table)*) > - -<!ELEMENT insidecover (#PCDATA|br|theheader|vfill|vspace|tt|bold| - include)* > -<!ELEMENT tt (#PCDATA|br|theheader|vfill)* > -<!ELEMENT bold (#PCDATA|br|theheader|vfill)* > -<!ELEMENT vfill EMPTY > -<!ELEMENT theheader EMPTY > -<!ATTLIST theheader tag (title|prepared|responsible|docno| - approved|checked|date|rev|file| - abbreviation| - none) "none" > - - -<!ELEMENT applications (include)* > -<!ELEMENT parts (title?,description?,(include|onepart)*) > -<!ATTLIST parts lift (yes|no) "no" > -<!ELEMENT headline (#PCDATA) > -<!ELEMENT index EMPTY > -<!ELEMENT listoffigures EMPTY > -<!ELEMENT listoftables EMPTY > -<!ELEMENT listofterms EMPTY > -<!ELEMENT bibliography EMPTY > -<!ELEMENT contents EMPTY > -<!ATTLIST contents level (0|1|2|3) "2"> - -<!ELEMENT onepart (title?,description?,include+) > -<!ATTLIST onepart lift (yes|no) "no" > - -<!ELEMENT description (%block;|quote|br|marker|warning|note)* > - -<!ELEMENT include EMPTY > -<!ATTLIST include file CDATA #REQUIRED> diff --git a/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd b/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd deleted file mode 100644 index d6efbef6a4..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > - -<!ELEMENT bookinsidecover (#PCDATA|br|theheader|vfill|tt|bold)* > - -<!ELEMENT tt (#PCDATA|br|theheader|vfill)* > -<!ELEMENT bold (#PCDATA|br|theheader|vfill)* > -<!ELEMENT vfill EMPTY > -<!ELEMENT theheader EMPTY > -<!ATTLIST theheader tag (title|prepared|responsible|docno| - approved|checked|date|rev|file| - none) "none" > - -<!ELEMENT br EMPTY > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd b/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd deleted file mode 100644 index eb2c96b04f..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common SYSTEM "common.dtd" > -%common; -<!ENTITY % common.header SYSTEM "common.header.dtd" > -%common.header; -<!ENTITY % common.table SYSTEM "common.table.dtd" > -%common.table; -<!ENTITY % common.image SYSTEM "common.image.dtd" > -%common.image; - -<!-- Structure --> - -<!ELEMENT chapter (header,(%block;|quote|warning|note|br| - image|marker|table)*,section+) > -<!ELEMENT section (marker*,title, - (%block;|quote|warning|note|br|image|marker| - table|section)*) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd b/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd deleted file mode 100644 index 334574bff9..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd +++ /dev/null @@ -1,35 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > - -<!-- Structure --> - -<!ELEMENT cites (cite)* > -<!ELEMENT cite (id, shortdef, def, resp?) > -<!ELEMENT id (#PCDATA) > -<!ELEMENT shortdef (#PCDATA) > -<!ELEMENT def (#PCDATA|c|em)* > -<!ELEMENT resp (#PCDATA) > -<!ELEMENT c (#PCDATA) > -<!ELEMENT em (#PCDATA|c)* > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd deleted file mode 100644 index f893ecd070..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd deleted file mode 100644 index d422a89693..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd +++ /dev/null @@ -1,42 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ELEMENT header (copyright?,legalnotice?,title,shorttitle?, - prepared,responsible?,docno,approved?, - checked?,date,rev,file?) > - -<!-- -The titlestyle attribute is only defined to make all the book.xml files -go through the validation. The attribute is not used for anything ---> -<!ATTLIST header titlestyle (special|normal) "normal"> - -<!ELEMENT title (#PCDATA) > -<!ELEMENT shorttitle (#PCDATA) > -<!ELEMENT prepared (#PCDATA) > -<!ELEMENT responsible (#PCDATA) > -<!ELEMENT docno (#PCDATA) > -<!ELEMENT approved (#PCDATA) > -<!ELEMENT checked (#PCDATA) > -<!ELEMENT copyright (year+,holder*) > -<!ELEMENT legalnotice (#PCDATA) > -<!ELEMENT date (#PCDATA) > -<!ELEMENT rev (#PCDATA) > -<!ELEMENT file (#PCDATA) > -<!ELEMENT year (#PCDATA) > -<!ELEMENT holder (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd deleted file mode 100644 index fc95a669dd..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd +++ /dev/null @@ -1,21 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ELEMENT image (icaption) > -<!ATTLIST image file CDATA #REQUIRED > -<!ELEMENT icaption (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd deleted file mode 100644 index 7741da1018..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd +++ /dev/null @@ -1,25 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ELEMENT table (row+,tcaption) > -<!ATTLIST table align (left|center|right) "center" > -<!ELEMENT row (cell+) > -<!ELEMENT cell (%inline;)* > -<!ATTLIST cell align (left|center|right) "left" - valign (top|middle|bottom) "middle" > -<!ELEMENT tcaption (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd deleted file mode 100644 index fcdea625d5..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common.refs SYSTEM "common.refs.dtd" > -%common.refs; - -<!ELEMENT comref (header,com,comsummary,description, - (section|funcs)*,authors?) > -<!ELEMENT com (#PCDATA) > -<!ELEMENT comsummary (#PCDATA) > - -<!-- `name' is used in common.refs.dtd and must therefore - be defined in each *ref. dtd --> -<!ELEMENT name (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd deleted file mode 100644 index e43bb2bf51..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common.refs SYSTEM "common.refs.dtd" > -%common.refs; - -<!ELEMENT cref (header,lib,libsummary,description, - (section|funcs)*,authors?) > -<!ELEMENT lib (#PCDATA) > -<!ELEMENT libsummary (#PCDATA) > - -<!-- `name' is used in common.refs.dtd and must therefore - be defined in each *ref. dtd --> -<!ELEMENT name (ret,nametext) > -<!ELEMENT ret (#PCDATA) > -<!ELEMENT nametext (#PCDATA) > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd b/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd deleted file mode 100644 index b14276a2c0..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > - -<!-- Structure --> - -<!ELEMENT fascicules (fascicule)+ > -<!ELEMENT fascicule (#PCDATA) > -<!ATTLIST fascicule file CDATA #REQUIRED - href CDATA #REQUIRED - entry (yes|no) "no" > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd deleted file mode 100644 index 5a1cc54afe..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common.refs SYSTEM "common.refs.dtd" > -%common.refs; - -<!ELEMENT fileref (header,file,filesummary,description, - (section|funcs)*,authors?) > -<!-- Note: ELEMENT file is already defined --> -<!ELEMENT filesummary (#PCDATA) > - -<!-- `name' is used in common.refs.dtd and must therefore - be defined in each *ref. dtd --> -<!ELEMENT name (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/part.dtd b/lib/erl_docgen/priv/docbuilder_dtd/part.dtd deleted file mode 100644 index 3f97199042..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/part.dtd +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % common SYSTEM "common.dtd" > -%common; -<!ENTITY % common.header SYSTEM "common.header.dtd" > -%common.header; - -<!ELEMENT part (header,description?,include+) > -<!ELEMENT description (%block;|quote|br|marker|warning|note)* > -<!ELEMENT include EMPTY > -<!ATTLIST include file CDATA #REQUIRED> diff --git a/lib/erl_docgen/priv/docbuilder_dtd/report.dtd b/lib/erl_docgen/priv/docbuilder_dtd/report.dtd deleted file mode 100644 index 3d07e6e5a7..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/report.dtd +++ /dev/null @@ -1,138 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> - -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > - -<!ENTITY % header "title,prepared,responsible,docno,approved, - checked,date,rev,file" > -<!ENTITY % block "p|pre|code|list|taglist|erlinclude| - codeinclude|erleval" > -<!ENTITY % inline "#PCDATA|i|b|c|em|term|cite|br|path|seealso| - url|marker" > - -<!-- Structure --> - -<!ELEMENT report (header,section+) > -<!ELEMENT header (title,prepared,responsible?,docno,approved?, - checked?,date,rev,file?) > -<!ELEMENT title (#PCDATA) > -<!ELEMENT prepared (#PCDATA) > -<!ELEMENT responsible (#PCDATA) > -<!ELEMENT docno (#PCDATA) > -<!ELEMENT approved (#PCDATA) > -<!ELEMENT checked (#PCDATA) > -<!ELEMENT date (#PCDATA) > -<!ELEMENT rev (#PCDATA) > -<!ELEMENT file (#PCDATA) > - -<!ELEMENT section (marker*,title, - (%block;|quote|warning|note|br|image|marker| - table|section)*) > -<!ELEMENT p (%inline;|index)* > -<!ELEMENT pre (#PCDATA|seealso|url|input)* > -<!ELEMENT input (#PCDATA|seealso|url)* > -<!ELEMENT code (#PCDATA) > -<!ATTLIST code type (erl|c|none) "none" > -<!ELEMENT quote (p)* > -<!ELEMENT warning (%block;|quote|br|image|marker|table)* > -<!ELEMENT note (%block;|quote|br|image|marker|table)* > -<!ELEMENT i (#PCDATA|b|c|em)* > -<!ELEMENT b (#PCDATA|i|c|em)* > -<!ELEMENT c (#PCDATA) > -<!ELEMENT em (#PCDATA|i|b|c)* > -<!ELEMENT term (termdef?) > -<!ATTLIST term id CDATA #REQUIRED > -<!ELEMENT termdef (#PCDATA) > -<!ELEMENT cite (citedef?) > -<!ATTLIST cite id CDATA #REQUIRED > -<!ELEMENT citedef (ctitle,cauthor,chowpublished) > -<!ELEMENT ctitle (#PCDATA) > -<!ELEMENT cauthor (#PCDATA) > -<!ELEMENT chowpublished (#PCDATA) > -<!ELEMENT br EMPTY > - -<!-- Path --> - -<!ELEMENT path (#PCDATA) > -<!ATTLIST path unix CDATA "" - windows CDATA "" > - -<!-- List --> - -<!ELEMENT list (item+) > -<!ATTLIST list type (ordered|bulleted) "bulleted" > -<!ELEMENT taglist (tag,item)+ > -<!ELEMENT tag (#PCDATA|i|b|c|em|seealso|url)* > -<!ELEMENT item (%inline;|%block;)* > - -<!-- Image --> - -<!ELEMENT image (icaption?) > -<!ATTLIST image file CDATA #REQUIRED > -<!ELEMENT icaption (#PCDATA) > - -<!-- References --> - -<!ELEMENT seealso (#PCDATA) > -<!ATTLIST seealso marker CDATA #REQUIRED > -<!ELEMENT url (#PCDATA) > -<!ATTLIST url href CDATA #REQUIRED > -<!ELEMENT marker EMPTY > -<!ATTLIST marker id CDATA #REQUIRED > - -<!-- Table --> - -<!ELEMENT table (row+,tcaption?) > -<!ATTLIST table width CDATA "0" - colspec CDATA "" > -<!ELEMENT row (cell+) > -<!ELEMENT cell (%inline;)* > -<!ATTLIST cell align (left|center|right) "left" - valign (top|middle|bottom) "middle" > -<!ELEMENT tcaption (#PCDATA) > - -<!-- ErlInclude --> - -<!ELEMENT erlinclude EMPTY > -<!ATTLIST erlinclude file CDATA #REQUIRED - tag CDATA #REQUIRED > - -<!-- CodeInclude --> - -<!ELEMENT codeinclude EMPTY > -<!ATTLIST codeinclude file CDATA #REQUIRED - tag CDATA "" - type (erl|c|none) "none" > - -<!-- ErlEval --> - -<!ELEMENT erleval EMPTY > -<!ATTLIST erleval expr CDATA #REQUIRED > - -<!-- Index FOR COMPATIBILITY --> - -<!ELEMENT index EMPTY > -<!ATTLIST index txt CDATA #REQUIRED > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd b/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd deleted file mode 100644 index 6105ec593e..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - ``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 AB. - Portions created by Ericsson are Copyright 1999-2007, Ericsson AB. - All Rights Reserved.'' - - $Id$ ---> -<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" > -%ISOlat1; - -<!ENTITY amp "&" > -<!ENTITY gt ">" > -<!ENTITY lt "<" > - -<!-- Structure --> - -<!ELEMENT terms (term)* > -<!ELEMENT term (id, shortdef, def, resp?) > -<!ELEMENT id (#PCDATA) > -<!ELEMENT shortdef (#PCDATA) > -<!ELEMENT def (#PCDATA|c|em)* > -<!ELEMENT resp (#PCDATA) > -<!ELEMENT c (#PCDATA) > -<!ELEMENT em (#PCDATA|c)* > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd deleted file mode 100644 index d128f2eb7c..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd +++ /dev/null @@ -1,1235 +0,0 @@ -<!-- - Extensible HTML version 1.0 Frameset DTD - - This is the same as HTML 4 Frameset except for - changes due to the differences between XML and SGML. - - Namespace = http://www.w3.org/1999/xhtml - - For further information, see: http://www.w3.org/TR/xhtml1 - - Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio), - All Rights Reserved. - - This DTD module is identified by the PUBLIC and SYSTEM identifiers: - - PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" - - $Revision: 1.2 $ - $Date: 2002/08/01 18:37:55 $ - ---> - -<!--================ Character mnemonic entities =========================--> - -<!ENTITY % HTMLlat1 PUBLIC - "-//W3C//ENTITIES Latin 1 for XHTML//EN" - "xhtml-lat1.ent"> -%HTMLlat1; - -<!ENTITY % HTMLsymbol PUBLIC - "-//W3C//ENTITIES Symbols for XHTML//EN" - "xhtml-symbol.ent"> -%HTMLsymbol; - -<!ENTITY % HTMLspecial PUBLIC - "-//W3C//ENTITIES Special for XHTML//EN" - "xhtml-special.ent"> -%HTMLspecial; - -<!--================== Imported Names ====================================--> - -<!ENTITY % ContentType "CDATA"> - <!-- media type, as per [RFC2045] --> - -<!ENTITY % ContentTypes "CDATA"> - <!-- comma-separated list of media types, as per [RFC2045] --> - -<!ENTITY % Charset "CDATA"> - <!-- a character encoding, as per [RFC2045] --> - -<!ENTITY % Charsets "CDATA"> - <!-- a space separated list of character encodings, as per [RFC2045] --> - -<!ENTITY % LanguageCode "NMTOKEN"> - <!-- a language code, as per [RFC3066] --> - -<!ENTITY % Character "CDATA"> - <!-- a single character, as per section 2.2 of [XML] --> - -<!ENTITY % Number "CDATA"> - <!-- one or more digits --> - -<!ENTITY % LinkTypes "CDATA"> - <!-- space-separated list of link types --> - -<!ENTITY % MediaDesc "CDATA"> - <!-- single or comma-separated list of media descriptors --> - -<!ENTITY % URI "CDATA"> - <!-- a Uniform Resource Identifier, see [RFC2396] --> - -<!ENTITY % UriList "CDATA"> - <!-- a space separated list of Uniform Resource Identifiers --> - -<!ENTITY % Datetime "CDATA"> - <!-- date and time information. ISO date format --> - -<!ENTITY % Script "CDATA"> - <!-- script expression --> - -<!ENTITY % StyleSheet "CDATA"> - <!-- style sheet data --> - -<!ENTITY % Text "CDATA"> - <!-- used for titles etc. --> - -<!ENTITY % FrameTarget "NMTOKEN"> - <!-- render in this frame --> - -<!ENTITY % Length "CDATA"> - <!-- nn for pixels or nn% for percentage length --> - -<!ENTITY % MultiLength "CDATA"> - <!-- pixel, percentage, or relative --> - -<!ENTITY % MultiLengths "CDATA"> - <!-- comma-separated list of MultiLength --> - -<!ENTITY % Pixels "CDATA"> - <!-- integer representing length in pixels --> - -<!-- these are used for image maps --> - -<!ENTITY % Shape "(rect|circle|poly|default)"> - -<!ENTITY % Coords "CDATA"> - <!-- comma separated list of lengths --> - -<!-- used for object, applet, img, input and iframe --> -<!ENTITY % ImgAlign "(top|middle|bottom|left|right)"> - -<!-- a color using sRGB: #RRGGBB as Hex values --> -<!ENTITY % Color "CDATA"> - -<!-- There are also 16 widely known color names with their sRGB values: - - Black = #000000 Green = #008000 - Silver = #C0C0C0 Lime = #00FF00 - Gray = #808080 Olive = #808000 - White = #FFFFFF Yellow = #FFFF00 - Maroon = #800000 Navy = #000080 - Red = #FF0000 Blue = #0000FF - Purple = #800080 Teal = #008080 - Fuchsia= #FF00FF Aqua = #00FFFF ---> - -<!--=================== Generic Attributes ===============================--> - -<!-- core attributes common to most elements - id document-wide unique id - class space separated list of classes - style associated style info - title advisory title/amplification ---> -<!ENTITY % coreattrs - "id ID #IMPLIED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED" - > - -<!-- internationalization attributes - lang language code (backwards compatible) - xml:lang language code (as per XML 1.0 spec) - dir direction for weak/neutral text ---> -<!ENTITY % i18n - "lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #IMPLIED" - > - -<!-- attributes for common UI events - onclick a pointer button was clicked - ondblclick a pointer button was double clicked - onmousedown a pointer button was pressed down - onmouseup a pointer button was released - onmousemove a pointer was moved onto the element - onmouseout a pointer was moved away from the element - onkeypress a key was pressed and released - onkeydown a key was pressed down - onkeyup a key was released ---> -<!ENTITY % events - "onclick %Script; #IMPLIED - ondblclick %Script; #IMPLIED - onmousedown %Script; #IMPLIED - onmouseup %Script; #IMPLIED - onmouseover %Script; #IMPLIED - onmousemove %Script; #IMPLIED - onmouseout %Script; #IMPLIED - onkeypress %Script; #IMPLIED - onkeydown %Script; #IMPLIED - onkeyup %Script; #IMPLIED" - > - -<!-- attributes for elements that can get the focus - accesskey accessibility key character - tabindex position in tabbing order - onfocus the element got the focus - onblur the element lost the focus ---> -<!ENTITY % focus - "accesskey %Character; #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED" - > - -<!ENTITY % attrs "%coreattrs; %i18n; %events;"> - -<!-- text alignment for p, div, h1-h6. The default is - align="left" for ltr headings, "right" for rtl --> - -<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED"> - -<!--=================== Text Elements ====================================--> - -<!ENTITY % special.extra - "object | applet | img | map | iframe"> - -<!ENTITY % special.basic - "br | span | bdo"> - -<!ENTITY % special - "%special.basic; | %special.extra;"> - -<!ENTITY % fontstyle.extra "big | small | font | basefont"> - -<!ENTITY % fontstyle.basic "tt | i | b | u - | s | strike "> - -<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;"> - -<!ENTITY % phrase.extra "sub | sup"> -<!ENTITY % phrase.basic "em | strong | dfn | code | q | - samp | kbd | var | cite | abbr | acronym"> - -<!ENTITY % phrase "%phrase.basic; | %phrase.extra;"> - -<!ENTITY % inline.forms "input | select | textarea | label | button"> - -<!-- these can occur at block or inline level --> -<!ENTITY % misc.inline "ins | del | script"> - -<!-- these can only occur at block level --> -<!ENTITY % misc "noscript | %misc.inline;"> - - -<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;"> - -<!-- %Inline; covers inline or "text-level" elements --> -<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*"> - -<!--================== Block level elements ==============================--> - -<!ENTITY % heading "h1|h2|h3|h4|h5|h6"> -<!ENTITY % lists "ul | ol | dl | menu | dir"> -<!ENTITY % blocktext "pre | hr | blockquote | address | center"> - -<!ENTITY % block - "p | %heading; | div | %lists; | %blocktext; | isindex | fieldset | table"> - -<!-- %Flow; mixes block and inline and is used for list items etc. --> -<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*"> - -<!--================== Content models for exclusions =====================--> - -<!-- a elements use %Inline; excluding a --> - -<!ENTITY % a.content - "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*"> - -<!-- pre uses %Inline excluding img, object, applet, big, small, - sub, sup, font, or basefont --> - -<!ENTITY % pre.content - "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; | - %inline.forms; | %misc.inline;)*"> - - -<!-- form uses %Flow; excluding form --> - -<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*"> - -<!-- button uses %Flow; but excludes a, form, form controls, iframe --> - -<!ENTITY % button.content - "(#PCDATA | p | %heading; | div | %lists; | %blocktext; | - table | br | span | bdo | object | applet | img | map | - %fontstyle; | %phrase; | %misc;)*"> - -<!--================ Document Structure ==================================--> - -<!-- the namespace URI designates the document profile --> - -<!ELEMENT html (head, frameset)> -<!ATTLIST html - %i18n; - id ID #IMPLIED - xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml' - > - -<!--================ Document Head =======================================--> - -<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*"> - -<!-- content model is %head.misc; combined with a single - title and an optional base element in any order --> - -<!ELEMENT head (%head.misc;, - ((title, %head.misc;, (base, %head.misc;)?) | - (base, %head.misc;, (title, %head.misc;))))> - -<!ATTLIST head - %i18n; - id ID #IMPLIED - profile %URI; #IMPLIED - > - -<!-- The title element is not considered part of the flow of text. - It should be displayed, for example as the page header or - window title. Exactly one title is required per document. - --> -<!ELEMENT title (#PCDATA)> -<!ATTLIST title - %i18n; - id ID #IMPLIED - > - -<!-- document base URI --> - -<!ELEMENT base EMPTY> -<!ATTLIST base - id ID #IMPLIED - href %URI; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- generic metainformation --> -<!ELEMENT meta EMPTY> -<!ATTLIST meta - %i18n; - id ID #IMPLIED - http-equiv CDATA #IMPLIED - name CDATA #IMPLIED - content CDATA #REQUIRED - scheme CDATA #IMPLIED - > - -<!-- - Relationship values can be used in principle: - - a) for document specific toolbars/menus when used - with the link element in document head e.g. - start, contents, previous, next, index, end, help - b) to link to a separate style sheet (rel="stylesheet") - c) to make a link to a script (rel="script") - d) by stylesheets to control how collections of - html nodes are rendered into printed documents - e) to make a link to a printable version of this document - e.g. a PostScript or PDF version (rel="alternate" media="print") ---> - -<!ELEMENT link EMPTY> -<!ATTLIST link - %attrs; - charset %Charset; #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - type %ContentType; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - media %MediaDesc; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- style info, which may include CDATA sections --> -<!ELEMENT style (#PCDATA)> -<!ATTLIST style - %i18n; - id ID #IMPLIED - type %ContentType; #REQUIRED - media %MediaDesc; #IMPLIED - title %Text; #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- script statements, which may include CDATA sections --> -<!ELEMENT script (#PCDATA)> -<!ATTLIST script - id ID #IMPLIED - charset %Charset; #IMPLIED - type %ContentType; #REQUIRED - language CDATA #IMPLIED - src %URI; #IMPLIED - defer (defer) #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- alternate content container for non script-based rendering --> - -<!ELEMENT noscript %Flow;> -<!ATTLIST noscript - %attrs; - > - -<!--======================= Frames =======================================--> - -<!-- only one noframes element permitted per document --> - -<!ELEMENT frameset (frameset|frame|noframes)*> -<!ATTLIST frameset - %coreattrs; - rows %MultiLengths; #IMPLIED - cols %MultiLengths; #IMPLIED - onload %Script; #IMPLIED - onunload %Script; #IMPLIED - > - -<!-- reserved frame names start with "_" otherwise starts with letter --> - -<!-- tiled window within frameset --> - -<!ELEMENT frame EMPTY> -<!ATTLIST frame - %coreattrs; - longdesc %URI; #IMPLIED - name NMTOKEN #IMPLIED - src %URI; #IMPLIED - frameborder (1|0) "1" - marginwidth %Pixels; #IMPLIED - marginheight %Pixels; #IMPLIED - noresize (noresize) #IMPLIED - scrolling (yes|no|auto) "auto" - > - -<!-- inline subwindow --> - -<!ELEMENT iframe %Flow;> -<!ATTLIST iframe - %coreattrs; - longdesc %URI; #IMPLIED - name NMTOKEN #IMPLIED - src %URI; #IMPLIED - frameborder (1|0) "1" - marginwidth %Pixels; #IMPLIED - marginheight %Pixels; #IMPLIED - scrolling (yes|no|auto) "auto" - align %ImgAlign; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - > - -<!-- alternate content container for non frame-based rendering --> - -<!ELEMENT noframes (body)> -<!ATTLIST noframes - %attrs; - > - -<!--=================== Document Body ====================================--> - -<!ELEMENT body %Flow;> -<!ATTLIST body - %attrs; - onload %Script; #IMPLIED - onunload %Script; #IMPLIED - background %URI; #IMPLIED - bgcolor %Color; #IMPLIED - text %Color; #IMPLIED - link %Color; #IMPLIED - vlink %Color; #IMPLIED - alink %Color; #IMPLIED - > - -<!ELEMENT div %Flow;> <!-- generic language/style container --> -<!ATTLIST div - %attrs; - %TextAlign; - > - -<!--=================== Paragraphs =======================================--> - -<!ELEMENT p %Inline;> -<!ATTLIST p - %attrs; - %TextAlign; - > - -<!--=================== Headings =========================================--> - -<!-- - There are six levels of headings from h1 (the most important) - to h6 (the least important). ---> - -<!ELEMENT h1 %Inline;> -<!ATTLIST h1 - %attrs; - %TextAlign; - > - -<!ELEMENT h2 %Inline;> -<!ATTLIST h2 - %attrs; - %TextAlign; - > - -<!ELEMENT h3 %Inline;> -<!ATTLIST h3 - %attrs; - %TextAlign; - > - -<!ELEMENT h4 %Inline;> -<!ATTLIST h4 - %attrs; - %TextAlign; - > - -<!ELEMENT h5 %Inline;> -<!ATTLIST h5 - %attrs; - %TextAlign; - > - -<!ELEMENT h6 %Inline;> -<!ATTLIST h6 - %attrs; - %TextAlign; - > - -<!--=================== Lists ============================================--> - -<!-- Unordered list bullet styles --> - -<!ENTITY % ULStyle "(disc|square|circle)"> - -<!-- Unordered list --> - -<!ELEMENT ul (li)+> -<!ATTLIST ul - %attrs; - type %ULStyle; #IMPLIED - compact (compact) #IMPLIED - > - -<!-- Ordered list numbering style - - 1 arabic numbers 1, 2, 3, ... - a lower alpha a, b, c, ... - A upper alpha A, B, C, ... - i lower roman i, ii, iii, ... - I upper roman I, II, III, ... - - The style is applied to the sequence number which by default - is reset to 1 for the first list item in an ordered list. ---> -<!ENTITY % OLStyle "CDATA"> - -<!-- Ordered (numbered) list --> - -<!ELEMENT ol (li)+> -<!ATTLIST ol - %attrs; - type %OLStyle; #IMPLIED - compact (compact) #IMPLIED - start %Number; #IMPLIED - > - -<!-- single column list (DEPRECATED) --> -<!ELEMENT menu (li)+> -<!ATTLIST menu - %attrs; - compact (compact) #IMPLIED - > - -<!-- multiple column list (DEPRECATED) --> -<!ELEMENT dir (li)+> -<!ATTLIST dir - %attrs; - compact (compact) #IMPLIED - > - -<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" --> -<!ENTITY % LIStyle "CDATA"> - -<!-- list item --> - -<!ELEMENT li %Flow;> -<!ATTLIST li - %attrs; - type %LIStyle; #IMPLIED - value %Number; #IMPLIED - > - -<!-- definition lists - dt for term, dd for its definition --> - -<!ELEMENT dl (dt|dd)+> -<!ATTLIST dl - %attrs; - compact (compact) #IMPLIED - > - -<!ELEMENT dt %Inline;> -<!ATTLIST dt - %attrs; - > - -<!ELEMENT dd %Flow;> -<!ATTLIST dd - %attrs; - > - -<!--=================== Address ==========================================--> - -<!-- information on author --> - -<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*> -<!ATTLIST address - %attrs; - > - -<!--=================== Horizontal Rule ==================================--> - -<!ELEMENT hr EMPTY> -<!ATTLIST hr - %attrs; - align (left|center|right) #IMPLIED - noshade (noshade) #IMPLIED - size %Pixels; #IMPLIED - width %Length; #IMPLIED - > - -<!--=================== Preformatted Text ================================--> - -<!-- content is %Inline; excluding - "img|object|applet|big|small|sub|sup|font|basefont" --> - -<!ELEMENT pre %pre.content;> -<!ATTLIST pre - %attrs; - width %Number; #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!--=================== Block-like Quotes ================================--> - -<!ELEMENT blockquote %Flow;> -<!ATTLIST blockquote - %attrs; - cite %URI; #IMPLIED - > - -<!--=================== Text alignment ===================================--> - -<!-- center content --> -<!ELEMENT center %Flow;> -<!ATTLIST center - %attrs; - > - -<!--=================== Inserted/Deleted Text ============================--> - - -<!-- - ins/del are allowed in block and inline content, but its - inappropriate to include block content within an ins element - occurring in inline content. ---> -<!ELEMENT ins %Flow;> -<!ATTLIST ins - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!ELEMENT del %Flow;> -<!ATTLIST del - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!--================== The Anchor Element ================================--> - -<!-- content is %Inline; except that anchors shouldn't be nested --> - -<!ELEMENT a %a.content;> -<!ATTLIST a - %attrs; - %focus; - charset %Charset; #IMPLIED - type %ContentType; #IMPLIED - name NMTOKEN #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - shape %Shape; "rect" - coords %Coords; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!--===================== Inline Elements ================================--> - -<!ELEMENT span %Inline;> <!-- generic language/style container --> -<!ATTLIST span - %attrs; - > - -<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride --> -<!ATTLIST bdo - %coreattrs; - %events; - lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #REQUIRED - > - -<!ELEMENT br EMPTY> <!-- forced line break --> -<!ATTLIST br - %coreattrs; - clear (left|all|right|none) "none" - > - -<!ELEMENT em %Inline;> <!-- emphasis --> -<!ATTLIST em %attrs;> - -<!ELEMENT strong %Inline;> <!-- strong emphasis --> -<!ATTLIST strong %attrs;> - -<!ELEMENT dfn %Inline;> <!-- definitional --> -<!ATTLIST dfn %attrs;> - -<!ELEMENT code %Inline;> <!-- program code --> -<!ATTLIST code %attrs;> - -<!ELEMENT samp %Inline;> <!-- sample --> -<!ATTLIST samp %attrs;> - -<!ELEMENT kbd %Inline;> <!-- something user would type --> -<!ATTLIST kbd %attrs;> - -<!ELEMENT var %Inline;> <!-- variable --> -<!ATTLIST var %attrs;> - -<!ELEMENT cite %Inline;> <!-- citation --> -<!ATTLIST cite %attrs;> - -<!ELEMENT abbr %Inline;> <!-- abbreviation --> -<!ATTLIST abbr %attrs;> - -<!ELEMENT acronym %Inline;> <!-- acronym --> -<!ATTLIST acronym %attrs;> - -<!ELEMENT q %Inline;> <!-- inlined quote --> -<!ATTLIST q - %attrs; - cite %URI; #IMPLIED - > - -<!ELEMENT sub %Inline;> <!-- subscript --> -<!ATTLIST sub %attrs;> - -<!ELEMENT sup %Inline;> <!-- superscript --> -<!ATTLIST sup %attrs;> - -<!ELEMENT tt %Inline;> <!-- fixed pitch font --> -<!ATTLIST tt %attrs;> - -<!ELEMENT i %Inline;> <!-- italic font --> -<!ATTLIST i %attrs;> - -<!ELEMENT b %Inline;> <!-- bold font --> -<!ATTLIST b %attrs;> - -<!ELEMENT big %Inline;> <!-- bigger font --> -<!ATTLIST big %attrs;> - -<!ELEMENT small %Inline;> <!-- smaller font --> -<!ATTLIST small %attrs;> - -<!ELEMENT u %Inline;> <!-- underline --> -<!ATTLIST u %attrs;> - -<!ELEMENT s %Inline;> <!-- strike-through --> -<!ATTLIST s %attrs;> - -<!ELEMENT strike %Inline;> <!-- strike-through --> -<!ATTLIST strike %attrs;> - -<!ELEMENT basefont EMPTY> <!-- base font size --> -<!ATTLIST basefont - id ID #IMPLIED - size CDATA #REQUIRED - color %Color; #IMPLIED - face CDATA #IMPLIED - > - -<!ELEMENT font %Inline;> <!-- local change to font --> -<!ATTLIST font - %coreattrs; - %i18n; - size CDATA #IMPLIED - color %Color; #IMPLIED - face CDATA #IMPLIED - > - -<!--==================== Object ======================================--> -<!-- - object is used to embed objects as part of HTML pages. - param elements should precede other content. Parameters - can also be expressed as attribute/value pairs on the - object element itself when brevity is desired. ---> - -<!ELEMENT object (#PCDATA | param | %block; | form |%inline; | %misc;)*> -<!ATTLIST object - %attrs; - declare (declare) #IMPLIED - classid %URI; #IMPLIED - codebase %URI; #IMPLIED - data %URI; #IMPLIED - type %ContentType; #IMPLIED - codetype %ContentType; #IMPLIED - archive %UriList; #IMPLIED - standby %Text; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - name NMTOKEN #IMPLIED - tabindex %Number; #IMPLIED - align %ImgAlign; #IMPLIED - border %Pixels; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!-- - param is used to supply a named property value. - In XML it would seem natural to follow RDF and support an - abbreviated syntax where the param elements are replaced - by attribute value pairs on the object start tag. ---> -<!ELEMENT param EMPTY> -<!ATTLIST param - id ID #IMPLIED - name CDATA #REQUIRED - value CDATA #IMPLIED - valuetype (data|ref|object) "data" - type %ContentType; #IMPLIED - > - -<!--=================== Java applet ==================================--> -<!-- - One of code or object attributes must be present. - Place param elements before other content. ---> -<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*> -<!ATTLIST applet - %coreattrs; - codebase %URI; #IMPLIED - archive CDATA #IMPLIED - code CDATA #IMPLIED - object CDATA #IMPLIED - alt %Text; #IMPLIED - name NMTOKEN #IMPLIED - width %Length; #REQUIRED - height %Length; #REQUIRED - align %ImgAlign; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!--=================== Images ===========================================--> - -<!-- - To avoid accessibility problems for people who aren't - able to see the image, you should provide a text - description using the alt and longdesc attributes. - In addition, avoid the use of server-side image maps. ---> - -<!ELEMENT img EMPTY> -<!ATTLIST img - %attrs; - src %URI; #REQUIRED - alt %Text; #REQUIRED - name NMTOKEN #IMPLIED - longdesc %URI; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - ismap (ismap) #IMPLIED - align %ImgAlign; #IMPLIED - border %Pixels; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!-- usemap points to a map element which may be in this document - or an external document, although the latter is not widely supported --> - -<!--================== Client-side image maps ============================--> - -<!-- These can be placed in the same document or grouped in a - separate document although this isn't yet widely supported --> - -<!ELEMENT map ((%block; | form | %misc;)+ | area+)> -<!ATTLIST map - %i18n; - %events; - id ID #REQUIRED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED - name NMTOKEN #IMPLIED - > - -<!ELEMENT area EMPTY> -<!ATTLIST area - %attrs; - %focus; - shape %Shape; "rect" - coords %Coords; #IMPLIED - href %URI; #IMPLIED - nohref (nohref) #IMPLIED - alt %Text; #REQUIRED - target %FrameTarget; #IMPLIED - > - -<!--================ Forms ===============================================--> - -<!ELEMENT form %form.content;> <!-- forms shouldn't be nested --> - -<!ATTLIST form - %attrs; - action %URI; #REQUIRED - method (get|post) "get" - name NMTOKEN #IMPLIED - enctype %ContentType; "application/x-www-form-urlencoded" - onsubmit %Script; #IMPLIED - onreset %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - accept-charset %Charsets; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- - Each label must not contain more than ONE field - Label elements shouldn't be nested. ---> -<!ELEMENT label %Inline;> -<!ATTLIST label - %attrs; - for IDREF #IMPLIED - accesskey %Character; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - > - -<!ENTITY % InputType - "(text | password | checkbox | - radio | submit | reset | - file | hidden | image | button)" - > - -<!-- the name attribute is required for all but submit & reset --> - -<!ELEMENT input EMPTY> <!-- form control --> -<!ATTLIST input - %attrs; - %focus; - type %InputType; "text" - name CDATA #IMPLIED - value CDATA #IMPLIED - checked (checked) #IMPLIED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - size CDATA #IMPLIED - maxlength %Number; #IMPLIED - src %URI; #IMPLIED - alt CDATA #IMPLIED - usemap %URI; #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - align %ImgAlign; #IMPLIED - > - -<!ELEMENT select (optgroup|option)+> <!-- option selector --> -<!ATTLIST select - %attrs; - name CDATA #IMPLIED - size %Number; #IMPLIED - multiple (multiple) #IMPLIED - disabled (disabled) #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!ELEMENT optgroup (option)+> <!-- option group --> -<!ATTLIST optgroup - %attrs; - disabled (disabled) #IMPLIED - label %Text; #REQUIRED - > - -<!ELEMENT option (#PCDATA)> <!-- selectable choice --> -<!ATTLIST option - %attrs; - selected (selected) #IMPLIED - disabled (disabled) #IMPLIED - label %Text; #IMPLIED - value CDATA #IMPLIED - > - -<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field --> -<!ATTLIST textarea - %attrs; - %focus; - name CDATA #IMPLIED - rows %Number; #REQUIRED - cols %Number; #REQUIRED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!-- - The fieldset element is used to group form fields. - Only one legend element should occur in the content - and if present should only be preceded by whitespace. ---> -<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*> -<!ATTLIST fieldset - %attrs; - > - -<!ENTITY % LAlign "(top|bottom|left|right)"> - -<!ELEMENT legend %Inline;> <!-- fieldset label --> -<!ATTLIST legend - %attrs; - accesskey %Character; #IMPLIED - align %LAlign; #IMPLIED - > - -<!-- - Content is %Flow; excluding a, form, form controls, iframe ---> -<!ELEMENT button %button.content;> <!-- push button --> -<!ATTLIST button - %attrs; - %focus; - name CDATA #IMPLIED - value CDATA #IMPLIED - type (button|submit|reset) "submit" - disabled (disabled) #IMPLIED - > - -<!-- single-line text input control (DEPRECATED) --> -<!ELEMENT isindex EMPTY> -<!ATTLIST isindex - %coreattrs; - %i18n; - prompt %Text; #IMPLIED - > - -<!--======================= Tables =======================================--> - -<!-- Derived from IETF HTML table standard, see [RFC1942] --> - -<!-- - The border attribute sets the thickness of the frame around the - table. The default units are screen pixels. - - The frame attribute specifies which parts of the frame around - the table should be rendered. The values are not the same as - CALS to avoid a name clash with the valign attribute. ---> -<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)"> - -<!-- - The rules attribute defines which rules to draw between cells: - - If rules is absent then assume: - "none" if border is absent or border="0" otherwise "all" ---> - -<!ENTITY % TRules "(none | groups | rows | cols | all)"> - -<!-- horizontal placement of table relative to document --> -<!ENTITY % TAlign "(left|center|right)"> - -<!-- horizontal alignment attributes for cell contents - - char alignment char, e.g. char=":" - charoff offset for alignment char ---> -<!ENTITY % cellhalign - "align (left|center|right|justify|char) #IMPLIED - char %Character; #IMPLIED - charoff %Length; #IMPLIED" - > - -<!-- vertical alignment attributes for cell contents --> -<!ENTITY % cellvalign - "valign (top|middle|bottom|baseline) #IMPLIED" - > - -<!ELEMENT table - (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))> -<!ELEMENT caption %Inline;> -<!ELEMENT thead (tr)+> -<!ELEMENT tfoot (tr)+> -<!ELEMENT tbody (tr)+> -<!ELEMENT colgroup (col)*> -<!ELEMENT col EMPTY> -<!ELEMENT tr (th|td)+> -<!ELEMENT th %Flow;> -<!ELEMENT td %Flow;> - -<!ATTLIST table - %attrs; - summary %Text; #IMPLIED - width %Length; #IMPLIED - border %Pixels; #IMPLIED - frame %TFrame; #IMPLIED - rules %TRules; #IMPLIED - cellspacing %Length; #IMPLIED - cellpadding %Length; #IMPLIED - align %TAlign; #IMPLIED - bgcolor %Color; #IMPLIED - > - -<!ENTITY % CAlign "(top|bottom|left|right)"> - -<!ATTLIST caption - %attrs; - align %CAlign; #IMPLIED - > - -<!-- -colgroup groups a set of col elements. It allows you to group -several semantically related columns together. ---> -<!ATTLIST colgroup - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - col elements define the alignment properties for cells in - one or more columns. - - The width attribute specifies the width of the columns, e.g. - - width=64 width in screen pixels - width=0.5* relative width of 0.5 - - The span attribute causes the attributes of one - col element to apply to more than one column. ---> -<!ATTLIST col - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - Use thead to duplicate headers when breaking table - across page boundaries, or for static headers when - tbody sections are rendered in scrolling panel. - - Use tfoot to duplicate footers when breaking table - across page boundaries, or for static footers when - tbody sections are rendered in scrolling panel. - - Use multiple tbody sections when rules are needed - between groups of table rows. ---> -<!ATTLIST thead - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tfoot - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tbody - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tr - %attrs; - %cellhalign; - %cellvalign; - bgcolor %Color; #IMPLIED - > - -<!-- Scope is simpler than headers attribute for common tables --> -<!ENTITY % Scope "(row|col|rowgroup|colgroup)"> - -<!-- th is for headers, td for data and for cells acting as both --> - -<!ATTLIST th - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - nowrap (nowrap) #IMPLIED - bgcolor %Color; #IMPLIED - width %Pixels; #IMPLIED - height %Pixels; #IMPLIED - > - -<!ATTLIST td - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - nowrap (nowrap) #IMPLIED - bgcolor %Color; #IMPLIED - width %Pixels; #IMPLIED - height %Pixels; #IMPLIED - > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd deleted file mode 100644 index 2927b9ece7..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd +++ /dev/null @@ -1,978 +0,0 @@ -<!-- - Extensible HTML version 1.0 Strict DTD - - This is the same as HTML 4 Strict except for - changes due to the differences between XML and SGML. - - Namespace = http://www.w3.org/1999/xhtml - - For further information, see: http://www.w3.org/TR/xhtml1 - - Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio), - All Rights Reserved. - - This DTD module is identified by the PUBLIC and SYSTEM identifiers: - - PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" - - $Revision: 1.1 $ - $Date: 2002/08/01 13:56:03 $ - ---> - -<!--================ Character mnemonic entities =========================--> - -<!ENTITY % HTMLlat1 PUBLIC - "-//W3C//ENTITIES Latin 1 for XHTML//EN" - "xhtml-lat1.ent"> -%HTMLlat1; - -<!ENTITY % HTMLsymbol PUBLIC - "-//W3C//ENTITIES Symbols for XHTML//EN" - "xhtml-symbol.ent"> -%HTMLsymbol; - -<!ENTITY % HTMLspecial PUBLIC - "-//W3C//ENTITIES Special for XHTML//EN" - "xhtml-special.ent"> -%HTMLspecial; - -<!--================== Imported Names ====================================--> - -<!ENTITY % ContentType "CDATA"> - <!-- media type, as per [RFC2045] --> - -<!ENTITY % ContentTypes "CDATA"> - <!-- comma-separated list of media types, as per [RFC2045] --> - -<!ENTITY % Charset "CDATA"> - <!-- a character encoding, as per [RFC2045] --> - -<!ENTITY % Charsets "CDATA"> - <!-- a space separated list of character encodings, as per [RFC2045] --> - -<!ENTITY % LanguageCode "NMTOKEN"> - <!-- a language code, as per [RFC3066] --> - -<!ENTITY % Character "CDATA"> - <!-- a single character, as per section 2.2 of [XML] --> - -<!ENTITY % Number "CDATA"> - <!-- one or more digits --> - -<!ENTITY % LinkTypes "CDATA"> - <!-- space-separated list of link types --> - -<!ENTITY % MediaDesc "CDATA"> - <!-- single or comma-separated list of media descriptors --> - -<!ENTITY % URI "CDATA"> - <!-- a Uniform Resource Identifier, see [RFC2396] --> - -<!ENTITY % UriList "CDATA"> - <!-- a space separated list of Uniform Resource Identifiers --> - -<!ENTITY % Datetime "CDATA"> - <!-- date and time information. ISO date format --> - -<!ENTITY % Script "CDATA"> - <!-- script expression --> - -<!ENTITY % StyleSheet "CDATA"> - <!-- style sheet data --> - -<!ENTITY % Text "CDATA"> - <!-- used for titles etc. --> - -<!ENTITY % Length "CDATA"> - <!-- nn for pixels or nn% for percentage length --> - -<!ENTITY % MultiLength "CDATA"> - <!-- pixel, percentage, or relative --> - -<!ENTITY % Pixels "CDATA"> - <!-- integer representing length in pixels --> - -<!-- these are used for image maps --> - -<!ENTITY % Shape "(rect|circle|poly|default)"> - -<!ENTITY % Coords "CDATA"> - <!-- comma separated list of lengths --> - -<!--=================== Generic Attributes ===============================--> - -<!-- core attributes common to most elements - id document-wide unique id - class space separated list of classes - style associated style info - title advisory title/amplification ---> -<!ENTITY % coreattrs - "id ID #IMPLIED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED" - > - -<!-- internationalization attributes - lang language code (backwards compatible) - xml:lang language code (as per XML 1.0 spec) - dir direction for weak/neutral text ---> -<!ENTITY % i18n - "lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #IMPLIED" - > - -<!-- attributes for common UI events - onclick a pointer button was clicked - ondblclick a pointer button was double clicked - onmousedown a pointer button was pressed down - onmouseup a pointer button was released - onmousemove a pointer was moved onto the element - onmouseout a pointer was moved away from the element - onkeypress a key was pressed and released - onkeydown a key was pressed down - onkeyup a key was released ---> -<!ENTITY % events - "onclick %Script; #IMPLIED - ondblclick %Script; #IMPLIED - onmousedown %Script; #IMPLIED - onmouseup %Script; #IMPLIED - onmouseover %Script; #IMPLIED - onmousemove %Script; #IMPLIED - onmouseout %Script; #IMPLIED - onkeypress %Script; #IMPLIED - onkeydown %Script; #IMPLIED - onkeyup %Script; #IMPLIED" - > - -<!-- attributes for elements that can get the focus - accesskey accessibility key character - tabindex position in tabbing order - onfocus the element got the focus - onblur the element lost the focus ---> -<!ENTITY % focus - "accesskey %Character; #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED" - > - -<!ENTITY % attrs "%coreattrs; %i18n; %events;"> - -<!--=================== Text Elements ====================================--> - -<!ENTITY % special.pre - "br | span | bdo | map"> - - -<!ENTITY % special - "%special.pre; | object | img "> - -<!ENTITY % fontstyle "tt | i | b | big | small "> - -<!ENTITY % phrase "em | strong | dfn | code | q | - samp | kbd | var | cite | abbr | acronym | sub | sup "> - -<!ENTITY % inline.forms "input | select | textarea | label | button"> - -<!-- these can occur at block or inline level --> -<!ENTITY % misc.inline "ins | del | script"> - -<!-- these can only occur at block level --> -<!ENTITY % misc "noscript | %misc.inline;"> - -<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;"> - -<!-- %Inline; covers inline or "text-level" elements --> -<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*"> - -<!--================== Block level elements ==============================--> - -<!ENTITY % heading "h1|h2|h3|h4|h5|h6"> -<!ENTITY % lists "ul | ol | dl"> -<!ENTITY % blocktext "pre | hr | blockquote | address"> - -<!ENTITY % block - "p | %heading; | div | %lists; | %blocktext; | fieldset | table"> - -<!ENTITY % Block "(%block; | form | %misc;)*"> - -<!-- %Flow; mixes block and inline and is used for list items etc. --> -<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*"> - -<!--================== Content models for exclusions =====================--> - -<!-- a elements use %Inline; excluding a --> - -<!ENTITY % a.content - "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*"> - -<!-- pre uses %Inline excluding big, small, sup or sup --> - -<!ENTITY % pre.content - "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline; - | %inline.forms;)*"> - -<!-- form uses %Block; excluding form --> - -<!ENTITY % form.content "(%block; | %misc;)*"> - -<!-- button uses %Flow; but excludes a, form and form controls --> - -<!ENTITY % button.content - "(#PCDATA | p | %heading; | div | %lists; | %blocktext; | - table | %special; | %fontstyle; | %phrase; | %misc;)*"> - -<!--================ Document Structure ==================================--> - -<!-- the namespace URI designates the document profile --> - -<!ELEMENT html (head, body)> -<!ATTLIST html - %i18n; - id ID #IMPLIED - xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml' - > - -<!--================ Document Head =======================================--> - -<!ENTITY % head.misc "(script|style|meta|link|object)*"> - -<!-- content model is %head.misc; combined with a single - title and an optional base element in any order --> - -<!ELEMENT head (%head.misc;, - ((title, %head.misc;, (base, %head.misc;)?) | - (base, %head.misc;, (title, %head.misc;))))> - -<!ATTLIST head - %i18n; - id ID #IMPLIED - profile %URI; #IMPLIED - > - -<!-- The title element is not considered part of the flow of text. - It should be displayed, for example as the page header or - window title. Exactly one title is required per document. - --> -<!ELEMENT title (#PCDATA)> -<!ATTLIST title - %i18n; - id ID #IMPLIED - > - -<!-- document base URI --> - -<!ELEMENT base EMPTY> -<!ATTLIST base - href %URI; #REQUIRED - id ID #IMPLIED - > - -<!-- generic metainformation --> -<!ELEMENT meta EMPTY> -<!ATTLIST meta - %i18n; - id ID #IMPLIED - http-equiv CDATA #IMPLIED - name CDATA #IMPLIED - content CDATA #REQUIRED - scheme CDATA #IMPLIED - > - -<!-- - Relationship values can be used in principle: - - a) for document specific toolbars/menus when used - with the link element in document head e.g. - start, contents, previous, next, index, end, help - b) to link to a separate style sheet (rel="stylesheet") - c) to make a link to a script (rel="script") - d) by stylesheets to control how collections of - html nodes are rendered into printed documents - e) to make a link to a printable version of this document - e.g. a PostScript or PDF version (rel="alternate" media="print") ---> - -<!ELEMENT link EMPTY> -<!ATTLIST link - %attrs; - charset %Charset; #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - type %ContentType; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - media %MediaDesc; #IMPLIED - > - -<!-- style info, which may include CDATA sections --> -<!ELEMENT style (#PCDATA)> -<!ATTLIST style - %i18n; - id ID #IMPLIED - type %ContentType; #REQUIRED - media %MediaDesc; #IMPLIED - title %Text; #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- script statements, which may include CDATA sections --> -<!ELEMENT script (#PCDATA)> -<!ATTLIST script - id ID #IMPLIED - charset %Charset; #IMPLIED - type %ContentType; #REQUIRED - src %URI; #IMPLIED - defer (defer) #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- alternate content container for non script-based rendering --> - -<!ELEMENT noscript %Block;> -<!ATTLIST noscript - %attrs; - > - -<!--=================== Document Body ====================================--> - -<!ELEMENT body %Block;> -<!ATTLIST body - %attrs; - onload %Script; #IMPLIED - onunload %Script; #IMPLIED - > - -<!ELEMENT div %Flow;> <!-- generic language/style container --> -<!ATTLIST div - %attrs; - > - -<!--=================== Paragraphs =======================================--> - -<!ELEMENT p %Inline;> -<!ATTLIST p - %attrs; - > - -<!--=================== Headings =========================================--> - -<!-- - There are six levels of headings from h1 (the most important) - to h6 (the least important). ---> - -<!ELEMENT h1 %Inline;> -<!ATTLIST h1 - %attrs; - > - -<!ELEMENT h2 %Inline;> -<!ATTLIST h2 - %attrs; - > - -<!ELEMENT h3 %Inline;> -<!ATTLIST h3 - %attrs; - > - -<!ELEMENT h4 %Inline;> -<!ATTLIST h4 - %attrs; - > - -<!ELEMENT h5 %Inline;> -<!ATTLIST h5 - %attrs; - > - -<!ELEMENT h6 %Inline;> -<!ATTLIST h6 - %attrs; - > - -<!--=================== Lists ============================================--> - -<!-- Unordered list --> - -<!ELEMENT ul (li)+> -<!ATTLIST ul - %attrs; - > - -<!-- Ordered (numbered) list --> - -<!ELEMENT ol (li)+> -<!ATTLIST ol - %attrs; - > - -<!-- list item --> - -<!ELEMENT li %Flow;> -<!ATTLIST li - %attrs; - > - -<!-- definition lists - dt for term, dd for its definition --> - -<!ELEMENT dl (dt|dd)+> -<!ATTLIST dl - %attrs; - > - -<!ELEMENT dt %Inline;> -<!ATTLIST dt - %attrs; - > - -<!ELEMENT dd %Flow;> -<!ATTLIST dd - %attrs; - > - -<!--=================== Address ==========================================--> - -<!-- information on author --> - -<!ELEMENT address %Inline;> -<!ATTLIST address - %attrs; - > - -<!--=================== Horizontal Rule ==================================--> - -<!ELEMENT hr EMPTY> -<!ATTLIST hr - %attrs; - > - -<!--=================== Preformatted Text ================================--> - -<!-- content is %Inline; excluding "img|object|big|small|sub|sup" --> - -<!ELEMENT pre %pre.content;> -<!ATTLIST pre - %attrs; - xml:space (preserve) #FIXED 'preserve' - > - -<!--=================== Block-like Quotes ================================--> - -<!ELEMENT blockquote %Block;> -<!ATTLIST blockquote - %attrs; - cite %URI; #IMPLIED - > - -<!--=================== Inserted/Deleted Text ============================--> - -<!-- - ins/del are allowed in block and inline content, but its - inappropriate to include block content within an ins element - occurring in inline content. ---> -<!ELEMENT ins %Flow;> -<!ATTLIST ins - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!ELEMENT del %Flow;> -<!ATTLIST del - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!--================== The Anchor Element ================================--> - -<!-- content is %Inline; except that anchors shouldn't be nested --> - -<!ELEMENT a %a.content;> -<!ATTLIST a - %attrs; - %focus; - charset %Charset; #IMPLIED - type %ContentType; #IMPLIED - name NMTOKEN #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - shape %Shape; "rect" - coords %Coords; #IMPLIED - > - -<!--===================== Inline Elements ================================--> - -<!ELEMENT span %Inline;> <!-- generic language/style container --> -<!ATTLIST span - %attrs; - > - -<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride --> -<!ATTLIST bdo - %coreattrs; - %events; - lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #REQUIRED - > - -<!ELEMENT br EMPTY> <!-- forced line break --> -<!ATTLIST br - %coreattrs; - > - -<!ELEMENT em %Inline;> <!-- emphasis --> -<!ATTLIST em %attrs;> - -<!ELEMENT strong %Inline;> <!-- strong emphasis --> -<!ATTLIST strong %attrs;> - -<!ELEMENT dfn %Inline;> <!-- definitional --> -<!ATTLIST dfn %attrs;> - -<!ELEMENT code %Inline;> <!-- program code --> -<!ATTLIST code %attrs;> - -<!ELEMENT samp %Inline;> <!-- sample --> -<!ATTLIST samp %attrs;> - -<!ELEMENT kbd %Inline;> <!-- something user would type --> -<!ATTLIST kbd %attrs;> - -<!ELEMENT var %Inline;> <!-- variable --> -<!ATTLIST var %attrs;> - -<!ELEMENT cite %Inline;> <!-- citation --> -<!ATTLIST cite %attrs;> - -<!ELEMENT abbr %Inline;> <!-- abbreviation --> -<!ATTLIST abbr %attrs;> - -<!ELEMENT acronym %Inline;> <!-- acronym --> -<!ATTLIST acronym %attrs;> - -<!ELEMENT q %Inline;> <!-- inlined quote --> -<!ATTLIST q - %attrs; - cite %URI; #IMPLIED - > - -<!ELEMENT sub %Inline;> <!-- subscript --> -<!ATTLIST sub %attrs;> - -<!ELEMENT sup %Inline;> <!-- superscript --> -<!ATTLIST sup %attrs;> - -<!ELEMENT tt %Inline;> <!-- fixed pitch font --> -<!ATTLIST tt %attrs;> - -<!ELEMENT i %Inline;> <!-- italic font --> -<!ATTLIST i %attrs;> - -<!ELEMENT b %Inline;> <!-- bold font --> -<!ATTLIST b %attrs;> - -<!ELEMENT big %Inline;> <!-- bigger font --> -<!ATTLIST big %attrs;> - -<!ELEMENT small %Inline;> <!-- smaller font --> -<!ATTLIST small %attrs;> - -<!--==================== Object ======================================--> -<!-- - object is used to embed objects as part of HTML pages. - param elements should precede other content. Parameters - can also be expressed as attribute/value pairs on the - object element itself when brevity is desired. ---> - -<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*> -<!ATTLIST object - %attrs; - declare (declare) #IMPLIED - classid %URI; #IMPLIED - codebase %URI; #IMPLIED - data %URI; #IMPLIED - type %ContentType; #IMPLIED - codetype %ContentType; #IMPLIED - archive %UriList; #IMPLIED - standby %Text; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - name NMTOKEN #IMPLIED - tabindex %Number; #IMPLIED - > - -<!-- - param is used to supply a named property value. - In XML it would seem natural to follow RDF and support an - abbreviated syntax where the param elements are replaced - by attribute value pairs on the object start tag. ---> -<!ELEMENT param EMPTY> -<!ATTLIST param - id ID #IMPLIED - name CDATA #IMPLIED - value CDATA #IMPLIED - valuetype (data|ref|object) "data" - type %ContentType; #IMPLIED - > - -<!--=================== Images ===========================================--> - -<!-- - To avoid accessibility problems for people who aren't - able to see the image, you should provide a text - description using the alt and longdesc attributes. - In addition, avoid the use of server-side image maps. - Note that in this DTD there is no name attribute. That - is only available in the transitional and frameset DTD. ---> - -<!ELEMENT img EMPTY> -<!ATTLIST img - %attrs; - src %URI; #REQUIRED - alt %Text; #REQUIRED - longdesc %URI; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - ismap (ismap) #IMPLIED - > - -<!-- usemap points to a map element which may be in this document - or an external document, although the latter is not widely supported --> - -<!--================== Client-side image maps ============================--> - -<!-- These can be placed in the same document or grouped in a - separate document although this isn't yet widely supported --> - -<!ELEMENT map ((%block; | form | %misc;)+ | area+)> -<!ATTLIST map - %i18n; - %events; - id ID #REQUIRED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED - name NMTOKEN #IMPLIED - > - -<!ELEMENT area EMPTY> -<!ATTLIST area - %attrs; - %focus; - shape %Shape; "rect" - coords %Coords; #IMPLIED - href %URI; #IMPLIED - nohref (nohref) #IMPLIED - alt %Text; #REQUIRED - > - -<!--================ Forms ===============================================--> -<!ELEMENT form %form.content;> <!-- forms shouldn't be nested --> - -<!ATTLIST form - %attrs; - action %URI; #REQUIRED - method (get|post) "get" - enctype %ContentType; "application/x-www-form-urlencoded" - onsubmit %Script; #IMPLIED - onreset %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - accept-charset %Charsets; #IMPLIED - > - -<!-- - Each label must not contain more than ONE field - Label elements shouldn't be nested. ---> -<!ELEMENT label %Inline;> -<!ATTLIST label - %attrs; - for IDREF #IMPLIED - accesskey %Character; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - > - -<!ENTITY % InputType - "(text | password | checkbox | - radio | submit | reset | - file | hidden | image | button)" - > - -<!-- the name attribute is required for all but submit & reset --> - -<!ELEMENT input EMPTY> <!-- form control --> -<!ATTLIST input - %attrs; - %focus; - type %InputType; "text" - name CDATA #IMPLIED - value CDATA #IMPLIED - checked (checked) #IMPLIED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - size CDATA #IMPLIED - maxlength %Number; #IMPLIED - src %URI; #IMPLIED - alt CDATA #IMPLIED - usemap %URI; #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - > - -<!ELEMENT select (optgroup|option)+> <!-- option selector --> -<!ATTLIST select - %attrs; - name CDATA #IMPLIED - size %Number; #IMPLIED - multiple (multiple) #IMPLIED - disabled (disabled) #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!ELEMENT optgroup (option)+> <!-- option group --> -<!ATTLIST optgroup - %attrs; - disabled (disabled) #IMPLIED - label %Text; #REQUIRED - > - -<!ELEMENT option (#PCDATA)> <!-- selectable choice --> -<!ATTLIST option - %attrs; - selected (selected) #IMPLIED - disabled (disabled) #IMPLIED - label %Text; #IMPLIED - value CDATA #IMPLIED - > - -<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field --> -<!ATTLIST textarea - %attrs; - %focus; - name CDATA #IMPLIED - rows %Number; #REQUIRED - cols %Number; #REQUIRED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!-- - The fieldset element is used to group form fields. - Only one legend element should occur in the content - and if present should only be preceded by whitespace. ---> -<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*> -<!ATTLIST fieldset - %attrs; - > - -<!ELEMENT legend %Inline;> <!-- fieldset label --> -<!ATTLIST legend - %attrs; - accesskey %Character; #IMPLIED - > - -<!-- - Content is %Flow; excluding a, form and form controls ---> -<!ELEMENT button %button.content;> <!-- push button --> -<!ATTLIST button - %attrs; - %focus; - name CDATA #IMPLIED - value CDATA #IMPLIED - type (button|submit|reset) "submit" - disabled (disabled) #IMPLIED - > - -<!--======================= Tables =======================================--> - -<!-- Derived from IETF HTML table standard, see [RFC1942] --> - -<!-- - The border attribute sets the thickness of the frame around the - table. The default units are screen pixels. - - The frame attribute specifies which parts of the frame around - the table should be rendered. The values are not the same as - CALS to avoid a name clash with the valign attribute. ---> -<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)"> - -<!-- - The rules attribute defines which rules to draw between cells: - - If rules is absent then assume: - "none" if border is absent or border="0" otherwise "all" ---> - -<!ENTITY % TRules "(none | groups | rows | cols | all)"> - -<!-- horizontal alignment attributes for cell contents - - char alignment char, e.g. char=':' - charoff offset for alignment char ---> -<!ENTITY % cellhalign - "align (left|center|right|justify|char) #IMPLIED - char %Character; #IMPLIED - charoff %Length; #IMPLIED" - > - -<!-- vertical alignment attributes for cell contents --> -<!ENTITY % cellvalign - "valign (top|middle|bottom|baseline) #IMPLIED" - > - -<!ELEMENT table - (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))> -<!ELEMENT caption %Inline;> -<!ELEMENT thead (tr)+> -<!ELEMENT tfoot (tr)+> -<!ELEMENT tbody (tr)+> -<!ELEMENT colgroup (col)*> -<!ELEMENT col EMPTY> -<!ELEMENT tr (th|td)+> -<!ELEMENT th %Flow;> -<!ELEMENT td %Flow;> - -<!ATTLIST table - %attrs; - summary %Text; #IMPLIED - width %Length; #IMPLIED - border %Pixels; #IMPLIED - frame %TFrame; #IMPLIED - rules %TRules; #IMPLIED - cellspacing %Length; #IMPLIED - cellpadding %Length; #IMPLIED - > - -<!ATTLIST caption - %attrs; - > - -<!-- -colgroup groups a set of col elements. It allows you to group -several semantically related columns together. ---> -<!ATTLIST colgroup - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - col elements define the alignment properties for cells in - one or more columns. - - The width attribute specifies the width of the columns, e.g. - - width=64 width in screen pixels - width=0.5* relative width of 0.5 - - The span attribute causes the attributes of one - col element to apply to more than one column. ---> -<!ATTLIST col - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - Use thead to duplicate headers when breaking table - across page boundaries, or for static headers when - tbody sections are rendered in scrolling panel. - - Use tfoot to duplicate footers when breaking table - across page boundaries, or for static footers when - tbody sections are rendered in scrolling panel. - - Use multiple tbody sections when rules are needed - between groups of table rows. ---> -<!ATTLIST thead - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tfoot - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tbody - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tr - %attrs; - %cellhalign; - %cellvalign; - > - - -<!-- Scope is simpler than headers attribute for common tables --> -<!ENTITY % Scope "(row|col|rowgroup|colgroup)"> - -<!-- th is for headers, td for data and for cells acting as both --> - -<!ATTLIST th - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - > - -<!ATTLIST td - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd deleted file mode 100644 index 628f27ac50..0000000000 --- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd +++ /dev/null @@ -1,1201 +0,0 @@ -<!-- - Extensible HTML version 1.0 Transitional DTD - - This is the same as HTML 4 Transitional except for - changes due to the differences between XML and SGML. - - Namespace = http://www.w3.org/1999/xhtml - - For further information, see: http://www.w3.org/TR/xhtml1 - - Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio), - All Rights Reserved. - - This DTD module is identified by the PUBLIC and SYSTEM identifiers: - - PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" - - $Revision: 1.2 $ - $Date: 2002/08/01 18:37:55 $ - ---> - -<!--================ Character mnemonic entities =========================--> - -<!ENTITY % HTMLlat1 PUBLIC - "-//W3C//ENTITIES Latin 1 for XHTML//EN" - "xhtml-lat1.ent"> -%HTMLlat1; - -<!ENTITY % HTMLsymbol PUBLIC - "-//W3C//ENTITIES Symbols for XHTML//EN" - "xhtml-symbol.ent"> -%HTMLsymbol; - -<!ENTITY % HTMLspecial PUBLIC - "-//W3C//ENTITIES Special for XHTML//EN" - "xhtml-special.ent"> -%HTMLspecial; - -<!--================== Imported Names ====================================--> - -<!ENTITY % ContentType "CDATA"> - <!-- media type, as per [RFC2045] --> - -<!ENTITY % ContentTypes "CDATA"> - <!-- comma-separated list of media types, as per [RFC2045] --> - -<!ENTITY % Charset "CDATA"> - <!-- a character encoding, as per [RFC2045] --> - -<!ENTITY % Charsets "CDATA"> - <!-- a space separated list of character encodings, as per [RFC2045] --> - -<!ENTITY % LanguageCode "NMTOKEN"> - <!-- a language code, as per [RFC3066] --> - -<!ENTITY % Character "CDATA"> - <!-- a single character, as per section 2.2 of [XML] --> - -<!ENTITY % Number "CDATA"> - <!-- one or more digits --> - -<!ENTITY % LinkTypes "CDATA"> - <!-- space-separated list of link types --> - -<!ENTITY % MediaDesc "CDATA"> - <!-- single or comma-separated list of media descriptors --> - -<!ENTITY % URI "CDATA"> - <!-- a Uniform Resource Identifier, see [RFC2396] --> - -<!ENTITY % UriList "CDATA"> - <!-- a space separated list of Uniform Resource Identifiers --> - -<!ENTITY % Datetime "CDATA"> - <!-- date and time information. ISO date format --> - -<!ENTITY % Script "CDATA"> - <!-- script expression --> - -<!ENTITY % StyleSheet "CDATA"> - <!-- style sheet data --> - -<!ENTITY % Text "CDATA"> - <!-- used for titles etc. --> - -<!ENTITY % FrameTarget "NMTOKEN"> - <!-- render in this frame --> - -<!ENTITY % Length "CDATA"> - <!-- nn for pixels or nn% for percentage length --> - -<!ENTITY % MultiLength "CDATA"> - <!-- pixel, percentage, or relative --> - -<!ENTITY % Pixels "CDATA"> - <!-- integer representing length in pixels --> - -<!-- these are used for image maps --> - -<!ENTITY % Shape "(rect|circle|poly|default)"> - -<!ENTITY % Coords "CDATA"> - <!-- comma separated list of lengths --> - -<!-- used for object, applet, img, input and iframe --> -<!ENTITY % ImgAlign "(top|middle|bottom|left|right)"> - -<!-- a color using sRGB: #RRGGBB as Hex values --> -<!ENTITY % Color "CDATA"> - -<!-- There are also 16 widely known color names with their sRGB values: - - Black = #000000 Green = #008000 - Silver = #C0C0C0 Lime = #00FF00 - Gray = #808080 Olive = #808000 - White = #FFFFFF Yellow = #FFFF00 - Maroon = #800000 Navy = #000080 - Red = #FF0000 Blue = #0000FF - Purple = #800080 Teal = #008080 - Fuchsia= #FF00FF Aqua = #00FFFF ---> - -<!--=================== Generic Attributes ===============================--> - -<!-- core attributes common to most elements - id document-wide unique id - class space separated list of classes - style associated style info - title advisory title/amplification ---> -<!ENTITY % coreattrs - "id ID #IMPLIED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED" - > - -<!-- internationalization attributes - lang language code (backwards compatible) - xml:lang language code (as per XML 1.0 spec) - dir direction for weak/neutral text ---> -<!ENTITY % i18n - "lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #IMPLIED" - > - -<!-- attributes for common UI events - onclick a pointer button was clicked - ondblclick a pointer button was double clicked - onmousedown a pointer button was pressed down - onmouseup a pointer button was released - onmousemove a pointer was moved onto the element - onmouseout a pointer was moved away from the element - onkeypress a key was pressed and released - onkeydown a key was pressed down - onkeyup a key was released ---> -<!ENTITY % events - "onclick %Script; #IMPLIED - ondblclick %Script; #IMPLIED - onmousedown %Script; #IMPLIED - onmouseup %Script; #IMPLIED - onmouseover %Script; #IMPLIED - onmousemove %Script; #IMPLIED - onmouseout %Script; #IMPLIED - onkeypress %Script; #IMPLIED - onkeydown %Script; #IMPLIED - onkeyup %Script; #IMPLIED" - > - -<!-- attributes for elements that can get the focus - accesskey accessibility key character - tabindex position in tabbing order - onfocus the element got the focus - onblur the element lost the focus ---> -<!ENTITY % focus - "accesskey %Character; #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED" - > - -<!ENTITY % attrs "%coreattrs; %i18n; %events;"> - -<!-- text alignment for p, div, h1-h6. The default is - align="left" for ltr headings, "right" for rtl --> - -<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED"> - -<!--=================== Text Elements ====================================--> - -<!ENTITY % special.extra - "object | applet | img | map | iframe"> - -<!ENTITY % special.basic - "br | span | bdo"> - -<!ENTITY % special - "%special.basic; | %special.extra;"> - -<!ENTITY % fontstyle.extra "big | small | font | basefont"> - -<!ENTITY % fontstyle.basic "tt | i | b | u - | s | strike "> - -<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;"> - -<!ENTITY % phrase.extra "sub | sup"> -<!ENTITY % phrase.basic "em | strong | dfn | code | q | - samp | kbd | var | cite | abbr | acronym"> - -<!ENTITY % phrase "%phrase.basic; | %phrase.extra;"> - -<!ENTITY % inline.forms "input | select | textarea | label | button"> - -<!-- these can occur at block or inline level --> -<!ENTITY % misc.inline "ins | del | script"> - -<!-- these can only occur at block level --> -<!ENTITY % misc "noscript | %misc.inline;"> - -<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;"> - -<!-- %Inline; covers inline or "text-level" elements --> -<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*"> - -<!--================== Block level elements ==============================--> - -<!ENTITY % heading "h1|h2|h3|h4|h5|h6"> -<!ENTITY % lists "ul | ol | dl | menu | dir"> -<!ENTITY % blocktext "pre | hr | blockquote | address | center | noframes"> - -<!ENTITY % block - "p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table"> - -<!-- %Flow; mixes block and inline and is used for list items etc. --> -<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*"> - -<!--================== Content models for exclusions =====================--> - -<!-- a elements use %Inline; excluding a --> - -<!ENTITY % a.content - "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*"> - -<!-- pre uses %Inline excluding img, object, applet, big, small, - font, or basefont --> - -<!ENTITY % pre.content - "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; | - %inline.forms; | %misc.inline;)*"> - -<!-- form uses %Flow; excluding form --> - -<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*"> - -<!-- button uses %Flow; but excludes a, form, form controls, iframe --> - -<!ENTITY % button.content - "(#PCDATA | p | %heading; | div | %lists; | %blocktext; | - table | br | span | bdo | object | applet | img | map | - %fontstyle; | %phrase; | %misc;)*"> - -<!--================ Document Structure ==================================--> - -<!-- the namespace URI designates the document profile --> - -<!ELEMENT html (head, body)> -<!ATTLIST html - %i18n; - id ID #IMPLIED - xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml' - > - -<!--================ Document Head =======================================--> - -<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*"> - -<!-- content model is %head.misc; combined with a single - title and an optional base element in any order --> - -<!ELEMENT head (%head.misc;, - ((title, %head.misc;, (base, %head.misc;)?) | - (base, %head.misc;, (title, %head.misc;))))> - -<!ATTLIST head - %i18n; - id ID #IMPLIED - profile %URI; #IMPLIED - > - -<!-- The title element is not considered part of the flow of text. - It should be displayed, for example as the page header or - window title. Exactly one title is required per document. - --> -<!ELEMENT title (#PCDATA)> -<!ATTLIST title - %i18n; - id ID #IMPLIED - > - -<!-- document base URI --> - -<!ELEMENT base EMPTY> -<!ATTLIST base - id ID #IMPLIED - href %URI; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- generic metainformation --> -<!ELEMENT meta EMPTY> -<!ATTLIST meta - %i18n; - id ID #IMPLIED - http-equiv CDATA #IMPLIED - name CDATA #IMPLIED - content CDATA #REQUIRED - scheme CDATA #IMPLIED - > - -<!-- - Relationship values can be used in principle: - - a) for document specific toolbars/menus when used - with the link element in document head e.g. - start, contents, previous, next, index, end, help - b) to link to a separate style sheet (rel="stylesheet") - c) to make a link to a script (rel="script") - d) by stylesheets to control how collections of - html nodes are rendered into printed documents - e) to make a link to a printable version of this document - e.g. a PostScript or PDF version (rel="alternate" media="print") ---> - -<!ELEMENT link EMPTY> -<!ATTLIST link - %attrs; - charset %Charset; #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - type %ContentType; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - media %MediaDesc; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- style info, which may include CDATA sections --> -<!ELEMENT style (#PCDATA)> -<!ATTLIST style - %i18n; - id ID #IMPLIED - type %ContentType; #REQUIRED - media %MediaDesc; #IMPLIED - title %Text; #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- script statements, which may include CDATA sections --> -<!ELEMENT script (#PCDATA)> -<!ATTLIST script - id ID #IMPLIED - charset %Charset; #IMPLIED - type %ContentType; #REQUIRED - language CDATA #IMPLIED - src %URI; #IMPLIED - defer (defer) #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!-- alternate content container for non script-based rendering --> - -<!ELEMENT noscript %Flow;> -<!ATTLIST noscript - %attrs; - > - -<!--======================= Frames =======================================--> - -<!-- inline subwindow --> - -<!ELEMENT iframe %Flow;> -<!ATTLIST iframe - %coreattrs; - longdesc %URI; #IMPLIED - name NMTOKEN #IMPLIED - src %URI; #IMPLIED - frameborder (1|0) "1" - marginwidth %Pixels; #IMPLIED - marginheight %Pixels; #IMPLIED - scrolling (yes|no|auto) "auto" - align %ImgAlign; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - > - -<!-- alternate content container for non frame-based rendering --> - -<!ELEMENT noframes %Flow;> -<!ATTLIST noframes - %attrs; - > - -<!--=================== Document Body ====================================--> - -<!ELEMENT body %Flow;> -<!ATTLIST body - %attrs; - onload %Script; #IMPLIED - onunload %Script; #IMPLIED - background %URI; #IMPLIED - bgcolor %Color; #IMPLIED - text %Color; #IMPLIED - link %Color; #IMPLIED - vlink %Color; #IMPLIED - alink %Color; #IMPLIED - > - -<!ELEMENT div %Flow;> <!-- generic language/style container --> -<!ATTLIST div - %attrs; - %TextAlign; - > - -<!--=================== Paragraphs =======================================--> - -<!ELEMENT p %Inline;> -<!ATTLIST p - %attrs; - %TextAlign; - > - -<!--=================== Headings =========================================--> - -<!-- - There are six levels of headings from h1 (the most important) - to h6 (the least important). ---> - -<!ELEMENT h1 %Inline;> -<!ATTLIST h1 - %attrs; - %TextAlign; - > - -<!ELEMENT h2 %Inline;> -<!ATTLIST h2 - %attrs; - %TextAlign; - > - -<!ELEMENT h3 %Inline;> -<!ATTLIST h3 - %attrs; - %TextAlign; - > - -<!ELEMENT h4 %Inline;> -<!ATTLIST h4 - %attrs; - %TextAlign; - > - -<!ELEMENT h5 %Inline;> -<!ATTLIST h5 - %attrs; - %TextAlign; - > - -<!ELEMENT h6 %Inline;> -<!ATTLIST h6 - %attrs; - %TextAlign; - > - -<!--=================== Lists ============================================--> - -<!-- Unordered list bullet styles --> - -<!ENTITY % ULStyle "(disc|square|circle)"> - -<!-- Unordered list --> - -<!ELEMENT ul (li)+> -<!ATTLIST ul - %attrs; - type %ULStyle; #IMPLIED - compact (compact) #IMPLIED - > - -<!-- Ordered list numbering style - - 1 arabic numbers 1, 2, 3, ... - a lower alpha a, b, c, ... - A upper alpha A, B, C, ... - i lower roman i, ii, iii, ... - I upper roman I, II, III, ... - - The style is applied to the sequence number which by default - is reset to 1 for the first list item in an ordered list. ---> -<!ENTITY % OLStyle "CDATA"> - -<!-- Ordered (numbered) list --> - -<!ELEMENT ol (li)+> -<!ATTLIST ol - %attrs; - type %OLStyle; #IMPLIED - compact (compact) #IMPLIED - start %Number; #IMPLIED - > - -<!-- single column list (DEPRECATED) --> -<!ELEMENT menu (li)+> -<!ATTLIST menu - %attrs; - compact (compact) #IMPLIED - > - -<!-- multiple column list (DEPRECATED) --> -<!ELEMENT dir (li)+> -<!ATTLIST dir - %attrs; - compact (compact) #IMPLIED - > - -<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" --> -<!ENTITY % LIStyle "CDATA"> - -<!-- list item --> - -<!ELEMENT li %Flow;> -<!ATTLIST li - %attrs; - type %LIStyle; #IMPLIED - value %Number; #IMPLIED - > - -<!-- definition lists - dt for term, dd for its definition --> - -<!ELEMENT dl (dt|dd)+> -<!ATTLIST dl - %attrs; - compact (compact) #IMPLIED - > - -<!ELEMENT dt %Inline;> -<!ATTLIST dt - %attrs; - > - -<!ELEMENT dd %Flow;> -<!ATTLIST dd - %attrs; - > - -<!--=================== Address ==========================================--> - -<!-- information on author --> - -<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*> -<!ATTLIST address - %attrs; - > - -<!--=================== Horizontal Rule ==================================--> - -<!ELEMENT hr EMPTY> -<!ATTLIST hr - %attrs; - align (left|center|right) #IMPLIED - noshade (noshade) #IMPLIED - size %Pixels; #IMPLIED - width %Length; #IMPLIED - > - -<!--=================== Preformatted Text ================================--> - -<!-- content is %Inline; excluding - "img|object|applet|big|small|sub|sup|font|basefont" --> - -<!ELEMENT pre %pre.content;> -<!ATTLIST pre - %attrs; - width %Number; #IMPLIED - xml:space (preserve) #FIXED 'preserve' - > - -<!--=================== Block-like Quotes ================================--> - -<!ELEMENT blockquote %Flow;> -<!ATTLIST blockquote - %attrs; - cite %URI; #IMPLIED - > - -<!--=================== Text alignment ===================================--> - -<!-- center content --> -<!ELEMENT center %Flow;> -<!ATTLIST center - %attrs; - > - -<!--=================== Inserted/Deleted Text ============================--> - -<!-- - ins/del are allowed in block and inline content, but its - inappropriate to include block content within an ins element - occurring in inline content. ---> -<!ELEMENT ins %Flow;> -<!ATTLIST ins - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!ELEMENT del %Flow;> -<!ATTLIST del - %attrs; - cite %URI; #IMPLIED - datetime %Datetime; #IMPLIED - > - -<!--================== The Anchor Element ================================--> - -<!-- content is %Inline; except that anchors shouldn't be nested --> - -<!ELEMENT a %a.content;> -<!ATTLIST a - %attrs; - %focus; - charset %Charset; #IMPLIED - type %ContentType; #IMPLIED - name NMTOKEN #IMPLIED - href %URI; #IMPLIED - hreflang %LanguageCode; #IMPLIED - rel %LinkTypes; #IMPLIED - rev %LinkTypes; #IMPLIED - shape %Shape; "rect" - coords %Coords; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!--===================== Inline Elements ================================--> - -<!ELEMENT span %Inline;> <!-- generic language/style container --> -<!ATTLIST span - %attrs; - > - -<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride --> -<!ATTLIST bdo - %coreattrs; - %events; - lang %LanguageCode; #IMPLIED - xml:lang %LanguageCode; #IMPLIED - dir (ltr|rtl) #REQUIRED - > - -<!ELEMENT br EMPTY> <!-- forced line break --> -<!ATTLIST br - %coreattrs; - clear (left|all|right|none) "none" - > - -<!ELEMENT em %Inline;> <!-- emphasis --> -<!ATTLIST em %attrs;> - -<!ELEMENT strong %Inline;> <!-- strong emphasis --> -<!ATTLIST strong %attrs;> - -<!ELEMENT dfn %Inline;> <!-- definitional --> -<!ATTLIST dfn %attrs;> - -<!ELEMENT code %Inline;> <!-- program code --> -<!ATTLIST code %attrs;> - -<!ELEMENT samp %Inline;> <!-- sample --> -<!ATTLIST samp %attrs;> - -<!ELEMENT kbd %Inline;> <!-- something user would type --> -<!ATTLIST kbd %attrs;> - -<!ELEMENT var %Inline;> <!-- variable --> -<!ATTLIST var %attrs;> - -<!ELEMENT cite %Inline;> <!-- citation --> -<!ATTLIST cite %attrs;> - -<!ELEMENT abbr %Inline;> <!-- abbreviation --> -<!ATTLIST abbr %attrs;> - -<!ELEMENT acronym %Inline;> <!-- acronym --> -<!ATTLIST acronym %attrs;> - -<!ELEMENT q %Inline;> <!-- inlined quote --> -<!ATTLIST q - %attrs; - cite %URI; #IMPLIED - > - -<!ELEMENT sub %Inline;> <!-- subscript --> -<!ATTLIST sub %attrs;> - -<!ELEMENT sup %Inline;> <!-- superscript --> -<!ATTLIST sup %attrs;> - -<!ELEMENT tt %Inline;> <!-- fixed pitch font --> -<!ATTLIST tt %attrs;> - -<!ELEMENT i %Inline;> <!-- italic font --> -<!ATTLIST i %attrs;> - -<!ELEMENT b %Inline;> <!-- bold font --> -<!ATTLIST b %attrs;> - -<!ELEMENT big %Inline;> <!-- bigger font --> -<!ATTLIST big %attrs;> - -<!ELEMENT small %Inline;> <!-- smaller font --> -<!ATTLIST small %attrs;> - -<!ELEMENT u %Inline;> <!-- underline --> -<!ATTLIST u %attrs;> - -<!ELEMENT s %Inline;> <!-- strike-through --> -<!ATTLIST s %attrs;> - -<!ELEMENT strike %Inline;> <!-- strike-through --> -<!ATTLIST strike %attrs;> - -<!ELEMENT basefont EMPTY> <!-- base font size --> -<!ATTLIST basefont - id ID #IMPLIED - size CDATA #REQUIRED - color %Color; #IMPLIED - face CDATA #IMPLIED - > - -<!ELEMENT font %Inline;> <!-- local change to font --> -<!ATTLIST font - %coreattrs; - %i18n; - size CDATA #IMPLIED - color %Color; #IMPLIED - face CDATA #IMPLIED - > - -<!--==================== Object ======================================--> -<!-- - object is used to embed objects as part of HTML pages. - param elements should precede other content. Parameters - can also be expressed as attribute/value pairs on the - object element itself when brevity is desired. ---> - -<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*> -<!ATTLIST object - %attrs; - declare (declare) #IMPLIED - classid %URI; #IMPLIED - codebase %URI; #IMPLIED - data %URI; #IMPLIED - type %ContentType; #IMPLIED - codetype %ContentType; #IMPLIED - archive %UriList; #IMPLIED - standby %Text; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - name NMTOKEN #IMPLIED - tabindex %Number; #IMPLIED - align %ImgAlign; #IMPLIED - border %Pixels; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!-- - param is used to supply a named property value. - In XML it would seem natural to follow RDF and support an - abbreviated syntax where the param elements are replaced - by attribute value pairs on the object start tag. ---> -<!ELEMENT param EMPTY> -<!ATTLIST param - id ID #IMPLIED - name CDATA #REQUIRED - value CDATA #IMPLIED - valuetype (data|ref|object) "data" - type %ContentType; #IMPLIED - > - -<!--=================== Java applet ==================================--> -<!-- - One of code or object attributes must be present. - Place param elements before other content. ---> -<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*> -<!ATTLIST applet - %coreattrs; - codebase %URI; #IMPLIED - archive CDATA #IMPLIED - code CDATA #IMPLIED - object CDATA #IMPLIED - alt %Text; #IMPLIED - name NMTOKEN #IMPLIED - width %Length; #REQUIRED - height %Length; #REQUIRED - align %ImgAlign; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!--=================== Images ===========================================--> - -<!-- - To avoid accessibility problems for people who aren't - able to see the image, you should provide a text - description using the alt and longdesc attributes. - In addition, avoid the use of server-side image maps. ---> - -<!ELEMENT img EMPTY> -<!ATTLIST img - %attrs; - src %URI; #REQUIRED - alt %Text; #REQUIRED - name NMTOKEN #IMPLIED - longdesc %URI; #IMPLIED - height %Length; #IMPLIED - width %Length; #IMPLIED - usemap %URI; #IMPLIED - ismap (ismap) #IMPLIED - align %ImgAlign; #IMPLIED - border %Length; #IMPLIED - hspace %Pixels; #IMPLIED - vspace %Pixels; #IMPLIED - > - -<!-- usemap points to a map element which may be in this document - or an external document, although the latter is not widely supported --> - -<!--================== Client-side image maps ============================--> - -<!-- These can be placed in the same document or grouped in a - separate document although this isn't yet widely supported --> - -<!ELEMENT map ((%block; | form | %misc;)+ | area+)> -<!ATTLIST map - %i18n; - %events; - id ID #REQUIRED - class CDATA #IMPLIED - style %StyleSheet; #IMPLIED - title %Text; #IMPLIED - name CDATA #IMPLIED - > - -<!ELEMENT area EMPTY> -<!ATTLIST area - %attrs; - %focus; - shape %Shape; "rect" - coords %Coords; #IMPLIED - href %URI; #IMPLIED - nohref (nohref) #IMPLIED - alt %Text; #REQUIRED - target %FrameTarget; #IMPLIED - > - -<!--================ Forms ===============================================--> - -<!ELEMENT form %form.content;> <!-- forms shouldn't be nested --> - -<!ATTLIST form - %attrs; - action %URI; #REQUIRED - method (get|post) "get" - name NMTOKEN #IMPLIED - enctype %ContentType; "application/x-www-form-urlencoded" - onsubmit %Script; #IMPLIED - onreset %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - accept-charset %Charsets; #IMPLIED - target %FrameTarget; #IMPLIED - > - -<!-- - Each label must not contain more than ONE field - Label elements shouldn't be nested. ---> -<!ELEMENT label %Inline;> -<!ATTLIST label - %attrs; - for IDREF #IMPLIED - accesskey %Character; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - > - -<!ENTITY % InputType - "(text | password | checkbox | - radio | submit | reset | - file | hidden | image | button)" - > - -<!-- the name attribute is required for all but submit & reset --> - -<!ELEMENT input EMPTY> <!-- form control --> -<!ATTLIST input - %attrs; - %focus; - type %InputType; "text" - name CDATA #IMPLIED - value CDATA #IMPLIED - checked (checked) #IMPLIED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - size CDATA #IMPLIED - maxlength %Number; #IMPLIED - src %URI; #IMPLIED - alt CDATA #IMPLIED - usemap %URI; #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - accept %ContentTypes; #IMPLIED - align %ImgAlign; #IMPLIED - > - -<!ELEMENT select (optgroup|option)+> <!-- option selector --> -<!ATTLIST select - %attrs; - name CDATA #IMPLIED - size %Number; #IMPLIED - multiple (multiple) #IMPLIED - disabled (disabled) #IMPLIED - tabindex %Number; #IMPLIED - onfocus %Script; #IMPLIED - onblur %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!ELEMENT optgroup (option)+> <!-- option group --> -<!ATTLIST optgroup - %attrs; - disabled (disabled) #IMPLIED - label %Text; #REQUIRED - > - -<!ELEMENT option (#PCDATA)> <!-- selectable choice --> -<!ATTLIST option - %attrs; - selected (selected) #IMPLIED - disabled (disabled) #IMPLIED - label %Text; #IMPLIED - value CDATA #IMPLIED - > - -<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field --> -<!ATTLIST textarea - %attrs; - %focus; - name CDATA #IMPLIED - rows %Number; #REQUIRED - cols %Number; #REQUIRED - disabled (disabled) #IMPLIED - readonly (readonly) #IMPLIED - onselect %Script; #IMPLIED - onchange %Script; #IMPLIED - > - -<!-- - The fieldset element is used to group form fields. - Only one legend element should occur in the content - and if present should only be preceded by whitespace. ---> -<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*> -<!ATTLIST fieldset - %attrs; - > - -<!ENTITY % LAlign "(top|bottom|left|right)"> - -<!ELEMENT legend %Inline;> <!-- fieldset label --> -<!ATTLIST legend - %attrs; - accesskey %Character; #IMPLIED - align %LAlign; #IMPLIED - > - -<!-- - Content is %Flow; excluding a, form, form controls, iframe ---> -<!ELEMENT button %button.content;> <!-- push button --> -<!ATTLIST button - %attrs; - %focus; - name CDATA #IMPLIED - value CDATA #IMPLIED - type (button|submit|reset) "submit" - disabled (disabled) #IMPLIED - > - -<!-- single-line text input control (DEPRECATED) --> -<!ELEMENT isindex EMPTY> -<!ATTLIST isindex - %coreattrs; - %i18n; - prompt %Text; #IMPLIED - > - -<!--======================= Tables =======================================--> - -<!-- Derived from IETF HTML table standard, see [RFC1942] --> - -<!-- - The border attribute sets the thickness of the frame around the - table. The default units are screen pixels. - - The frame attribute specifies which parts of the frame around - the table should be rendered. The values are not the same as - CALS to avoid a name clash with the valign attribute. ---> -<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)"> - -<!-- - The rules attribute defines which rules to draw between cells: - - If rules is absent then assume: - "none" if border is absent or border="0" otherwise "all" ---> - -<!ENTITY % TRules "(none | groups | rows | cols | all)"> - -<!-- horizontal placement of table relative to document --> -<!ENTITY % TAlign "(left|center|right)"> - -<!-- horizontal alignment attributes for cell contents - - char alignment char, e.g. char=':' - charoff offset for alignment char ---> -<!ENTITY % cellhalign - "align (left|center|right|justify|char) #IMPLIED - char %Character; #IMPLIED - charoff %Length; #IMPLIED" - > - -<!-- vertical alignment attributes for cell contents --> -<!ENTITY % cellvalign - "valign (top|middle|bottom|baseline) #IMPLIED" - > - -<!ELEMENT table - (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))> -<!ELEMENT caption %Inline;> -<!ELEMENT thead (tr)+> -<!ELEMENT tfoot (tr)+> -<!ELEMENT tbody (tr)+> -<!ELEMENT colgroup (col)*> -<!ELEMENT col EMPTY> -<!ELEMENT tr (th|td)+> -<!ELEMENT th %Flow;> -<!ELEMENT td %Flow;> - -<!ATTLIST table - %attrs; - summary %Text; #IMPLIED - width %Length; #IMPLIED - border %Pixels; #IMPLIED - frame %TFrame; #IMPLIED - rules %TRules; #IMPLIED - cellspacing %Length; #IMPLIED - cellpadding %Length; #IMPLIED - align %TAlign; #IMPLIED - bgcolor %Color; #IMPLIED - > - -<!ENTITY % CAlign "(top|bottom|left|right)"> - -<!ATTLIST caption - %attrs; - align %CAlign; #IMPLIED - > - -<!-- -colgroup groups a set of col elements. It allows you to group -several semantically related columns together. ---> -<!ATTLIST colgroup - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - col elements define the alignment properties for cells in - one or more columns. - - The width attribute specifies the width of the columns, e.g. - - width=64 width in screen pixels - width=0.5* relative width of 0.5 - - The span attribute causes the attributes of one - col element to apply to more than one column. ---> -<!ATTLIST col - %attrs; - span %Number; "1" - width %MultiLength; #IMPLIED - %cellhalign; - %cellvalign; - > - -<!-- - Use thead to duplicate headers when breaking table - across page boundaries, or for static headers when - tbody sections are rendered in scrolling panel. - - Use tfoot to duplicate footers when breaking table - across page boundaries, or for static footers when - tbody sections are rendered in scrolling panel. - - Use multiple tbody sections when rules are needed - between groups of table rows. ---> -<!ATTLIST thead - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tfoot - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tbody - %attrs; - %cellhalign; - %cellvalign; - > - -<!ATTLIST tr - %attrs; - %cellhalign; - %cellvalign; - bgcolor %Color; #IMPLIED - > - -<!-- Scope is simpler than headers attribute for common tables --> -<!ENTITY % Scope "(row|col|rowgroup|colgroup)"> - -<!-- th is for headers, td for data and for cells acting as both --> - -<!ATTLIST th - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - nowrap (nowrap) #IMPLIED - bgcolor %Color; #IMPLIED - width %Length; #IMPLIED - height %Length; #IMPLIED - > - -<!ATTLIST td - %attrs; - abbr %Text; #IMPLIED - axis CDATA #IMPLIED - headers IDREFS #IMPLIED - scope %Scope; #IMPLIED - rowspan %Number; "1" - colspan %Number; "1" - %cellhalign; - %cellvalign; - nowrap (nowrap) #IMPLIED - bgcolor %Color; #IMPLIED - width %Length; #IMPLIED - height %Length; #IMPLIED - > - diff --git a/lib/erl_docgen/priv/docbuilder_dtd/Makefile b/lib/erl_docgen/priv/dtd/Makefile index e2214107cb..9454147258 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/Makefile +++ b/lib/erl_docgen/priv/dtd/Makefile @@ -62,7 +62,9 @@ DTD_FILES = \ fascicules.dtd \ terms.dtd - +ENT_FILES = \ + xhtml-special.ent \ + xhtml-symbol.ent # ---------------------------------------------------- # FLAGS @@ -87,8 +89,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/priv/docbuilder_dtd - $(INSTALL_DATA) $(DTD_FILES) $(RELSYSDIR)/priv/docbuilder_dtd + $(INSTALL_DIR) $(RELSYSDIR)/priv/dtd + $(INSTALL_DATA) $(DTD_FILES) $(ENT_FILES) $(RELSYSDIR)/priv/dtd release_docs_spec: diff --git a/lib/docbuilder/dtd/application.dtd b/lib/erl_docgen/priv/dtd/application.dtd index 8a1e8832ec..8a1e8832ec 100644 --- a/lib/docbuilder/dtd/application.dtd +++ b/lib/erl_docgen/priv/dtd/application.dtd diff --git a/lib/docbuilder/dtd/appref.dtd b/lib/erl_docgen/priv/dtd/appref.dtd index 70a5ff37af..70a5ff37af 100644 --- a/lib/docbuilder/dtd/appref.dtd +++ b/lib/erl_docgen/priv/dtd/appref.dtd diff --git a/lib/docbuilder/dtd/book.dtd b/lib/erl_docgen/priv/dtd/book.dtd index bb89a6d255..bb89a6d255 100644 --- a/lib/docbuilder/dtd/book.dtd +++ b/lib/erl_docgen/priv/dtd/book.dtd diff --git a/lib/docbuilder/dtd/bookinsidecover.dtd b/lib/erl_docgen/priv/dtd/bookinsidecover.dtd index d6efbef6a4..d6efbef6a4 100644 --- a/lib/docbuilder/dtd/bookinsidecover.dtd +++ b/lib/erl_docgen/priv/dtd/bookinsidecover.dtd diff --git a/lib/docbuilder/dtd/chapter.dtd b/lib/erl_docgen/priv/dtd/chapter.dtd index eb2c96b04f..eb2c96b04f 100644 --- a/lib/docbuilder/dtd/chapter.dtd +++ b/lib/erl_docgen/priv/dtd/chapter.dtd diff --git a/lib/docbuilder/dtd/cites.dtd b/lib/erl_docgen/priv/dtd/cites.dtd index 334574bff9..334574bff9 100644 --- a/lib/docbuilder/dtd/cites.dtd +++ b/lib/erl_docgen/priv/dtd/cites.dtd diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd index fdc02c55a1..fdc02c55a1 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.dtd +++ b/lib/erl_docgen/priv/dtd/common.dtd diff --git a/lib/docbuilder/dtd/common.entities.dtd b/lib/erl_docgen/priv/dtd/common.entities.dtd index f893ecd070..f893ecd070 100644 --- a/lib/docbuilder/dtd/common.entities.dtd +++ b/lib/erl_docgen/priv/dtd/common.entities.dtd diff --git a/lib/docbuilder/dtd/common.header.dtd b/lib/erl_docgen/priv/dtd/common.header.dtd index d422a89693..d422a89693 100644 --- a/lib/docbuilder/dtd/common.header.dtd +++ b/lib/erl_docgen/priv/dtd/common.header.dtd diff --git a/lib/docbuilder/dtd/common.image.dtd b/lib/erl_docgen/priv/dtd/common.image.dtd index fc95a669dd..fc95a669dd 100644 --- a/lib/docbuilder/dtd/common.image.dtd +++ b/lib/erl_docgen/priv/dtd/common.image.dtd diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd index c1237766e1..c1237766e1 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd +++ b/lib/erl_docgen/priv/dtd/common.refs.dtd diff --git a/lib/docbuilder/dtd/common.table.dtd b/lib/erl_docgen/priv/dtd/common.table.dtd index 7741da1018..7741da1018 100644 --- a/lib/docbuilder/dtd/common.table.dtd +++ b/lib/erl_docgen/priv/dtd/common.table.dtd diff --git a/lib/docbuilder/dtd/comref.dtd b/lib/erl_docgen/priv/dtd/comref.dtd index fcdea625d5..fcdea625d5 100644 --- a/lib/docbuilder/dtd/comref.dtd +++ b/lib/erl_docgen/priv/dtd/comref.dtd diff --git a/lib/docbuilder/dtd/cref.dtd b/lib/erl_docgen/priv/dtd/cref.dtd index e43bb2bf51..e43bb2bf51 100644 --- a/lib/docbuilder/dtd/cref.dtd +++ b/lib/erl_docgen/priv/dtd/cref.dtd diff --git a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd index 9905086ff4..9905086ff4 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd +++ b/lib/erl_docgen/priv/dtd/erlref.dtd diff --git a/lib/docbuilder/dtd/fascicules.dtd b/lib/erl_docgen/priv/dtd/fascicules.dtd index b14276a2c0..b14276a2c0 100644 --- a/lib/docbuilder/dtd/fascicules.dtd +++ b/lib/erl_docgen/priv/dtd/fascicules.dtd diff --git a/lib/docbuilder/dtd/fileref.dtd b/lib/erl_docgen/priv/dtd/fileref.dtd index 5a1cc54afe..5a1cc54afe 100644 --- a/lib/docbuilder/dtd/fileref.dtd +++ b/lib/erl_docgen/priv/dtd/fileref.dtd diff --git a/lib/docbuilder/dtd/part.dtd b/lib/erl_docgen/priv/dtd/part.dtd index 3f97199042..3f97199042 100644 --- a/lib/docbuilder/dtd/part.dtd +++ b/lib/erl_docgen/priv/dtd/part.dtd diff --git a/lib/docbuilder/dtd/report.dtd b/lib/erl_docgen/priv/dtd/report.dtd index 3d07e6e5a7..3d07e6e5a7 100644 --- a/lib/docbuilder/dtd/report.dtd +++ b/lib/erl_docgen/priv/dtd/report.dtd diff --git a/lib/docbuilder/dtd/terms.dtd b/lib/erl_docgen/priv/dtd/terms.dtd index 6105ec593e..6105ec593e 100644 --- a/lib/docbuilder/dtd/terms.dtd +++ b/lib/erl_docgen/priv/dtd/terms.dtd diff --git a/lib/docbuilder/dtd/xhtml-special.ent b/lib/erl_docgen/priv/dtd/xhtml-special.ent index ca358b2fec..ca358b2fec 100644 --- a/lib/docbuilder/dtd/xhtml-special.ent +++ b/lib/erl_docgen/priv/dtd/xhtml-special.ent diff --git a/lib/docbuilder/dtd/xhtml-symbol.ent b/lib/erl_docgen/priv/dtd/xhtml-symbol.ent index 63c2abfa6f..63c2abfa6f 100644 --- a/lib/docbuilder/dtd/xhtml-symbol.ent +++ b/lib/erl_docgen/priv/dtd/xhtml-symbol.ent diff --git a/lib/docbuilder/dtd/xhtml1-frameset.dtd b/lib/erl_docgen/priv/dtd/xhtml1-frameset.dtd index d128f2eb7c..d128f2eb7c 100644 --- a/lib/docbuilder/dtd/xhtml1-frameset.dtd +++ b/lib/erl_docgen/priv/dtd/xhtml1-frameset.dtd diff --git a/lib/docbuilder/dtd/xhtml1-strict.dtd b/lib/erl_docgen/priv/dtd/xhtml1-strict.dtd index 2927b9ece7..2927b9ece7 100644 --- a/lib/docbuilder/dtd/xhtml1-strict.dtd +++ b/lib/erl_docgen/priv/dtd/xhtml1-strict.dtd diff --git a/lib/docbuilder/dtd/xhtml1-transitional.dtd b/lib/erl_docgen/priv/dtd/xhtml1-transitional.dtd index 628f27ac50..628f27ac50 100644 --- a/lib/docbuilder/dtd/xhtml1-transitional.dtd +++ b/lib/erl_docgen/priv/dtd/xhtml1-transitional.dtd diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl index 7a648ddfd7..55540317f6 100644 --- a/lib/erl_docgen/priv/xsl/db_eix.xsl +++ b/lib/erl_docgen/priv/xsl/db_eix.xsl @@ -106,10 +106,14 @@ <xsl:choose> <!-- @arity is mandatory when referring to a specification --> <xsl:when test="string-length(@arity) > 0"> - <xsl:call-template name="spec_name"/> + <xsl:call-template name="spec_name"> + <xsl:with-param name="lastfuncsblock" select="$lastfuncsblock"/> + </xsl:call-template> </xsl:when> <xsl:otherwise> - <xsl:call-template name="name"/> + <xsl:call-template name="name"> + <xsl:with-param name="lastfuncsblock" select="$lastfuncsblock"/> + </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile index 8e81bccd59..4a805697e6 100644 --- a/lib/erl_docgen/src/Makefile +++ b/lib/erl_docgen/src/Makefile @@ -35,7 +35,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/erl_docgen-$(VSN) # Target Specs # ---------------------------------------------------- MODULES = \ - otp_specs + docgen_otp_specs \ + docgen_edoc_xml_cb \ + docgen_xmerl_xml_cb HRL_FILES = diff --git a/lib/docbuilder/src/docb_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl index 90491bc007..dc9bc565ee 100644 --- a/lib/docbuilder/src/docb_edoc_xml_cb.erl +++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl @@ -15,17 +15,13 @@ %% %% $Id$ %% --module(docb_edoc_xml_cb). +-module(docgen_edoc_xml_cb). -%% This is the EDoc callback module for creating DocBuilder erlref -%% documents (man pages) in XML format, and also a DocBuilder chapter +%% This is the EDoc callback module for creating erlref +%% documents (man pages) in XML format, and also a 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"}, +%% edoc:file(File, [{layout,docgen_edoc_xml_cb},{file_suffix,".xml"}, %% {preprocess,true}]). %% %% The origin of this file is the edoc module otpsgml_layout.erl @@ -43,12 +39,12 @@ module(Element, Opts) -> SortP = proplists:get_value(sort_functions, Opts, true), XML = layout_module(Element, SortP), - xmerl:export_simple([XML], docb_xmerl_xml_cb, []). + xmerl:export_simple([XML], docgen_xmerl_xml_cb, []). %% CHAPTER overview(Element, _Opts) -> XML = layout_chapter(Element), - xmerl:export_simple([XML], docb_xmerl_xml_cb, []). + xmerl:export_simple([XML], docgen_xmerl_xml_cb, []). %%--Internal functions-------------------------------------------------- @@ -433,12 +429,11 @@ otp_xmlify_e(E) -> %% 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). +%% sure a .xml/.html file extension is removed. %% 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. +%% value "OTPROOT/..." (due to app_default being set to "OTPROOT") +%% , in this case both href attribute and content must be +%% formatted correctly according to requirements. otp_xmlify_a(A) -> [Attr0] = filter_a_attrs(A#xmlElement.attributes), case Attr0 of @@ -521,9 +516,8 @@ otp_xmlify_a_fileref(FileRef1, AppS) -> 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. + %% The marker automatically inserted 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 diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl index edb437a942..3929e66515 100644 --- a/lib/erl_docgen/src/otp_specs.erl +++ b/lib/erl_docgen/src/docgen_otp_specs.erl @@ -17,7 +17,7 @@ %% %CopyrightEnd% %% --module(otp_specs). +-module(docgen_otp_specs). -export([module/2, package/2, overview/2, type/1]). diff --git a/lib/docbuilder/src/docb_xmerl_xml_cb.erl b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl index 089b8f0c7d..884932ed12 100644 --- a/lib/docbuilder/src/docb_xmerl_xml_cb.erl +++ b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl @@ -15,11 +15,11 @@ %% %% $Id$ %% --module(docb_xmerl_xml_cb). +-module(docgen_xmerl_xml_cb). -%% This is the callback module for exporting XHTML to a DocBuilder +%% This is the callback module for exporting XHTML to an %% erlref or chapter document in XML format. -%% See docb_edoc_xml_cb.erl for further information. +%% See docgen_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. @@ -83,6 +83,6 @@ 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 + "" -> false; % no extension = xml file + _Ext -> true % extension end. diff --git a/lib/docbuilder/src/docb_xml_check.erl b/lib/erl_docgen/src/docgen_xml_check.erl index 5912e22e7b..892a880269 100644 --- a/lib/docbuilder/src/docb_xml_check.erl +++ b/lib/erl_docgen/src/docgen_xml_check.erl @@ -15,7 +15,7 @@ %% %% $Id$ %% --module(docb_xml_check). +-module(docgen_xml_check). -export([validate/1]). -deprecated([{validate,1,next_major_release}]). @@ -31,7 +31,7 @@ validate(File0) -> end, case filelib:is_regular(File) of true -> - DtdDir = docb_util:dtd_dir(), + DtdDir = filename:join(code:priv_dir(erl_docgen), "dtd"), case catch xmerl_scan:file(File, [{validation,true}, {fetch_path,[DtdDir]}]) of {'EXIT', Error} -> diff --git a/lib/erl_docgen/src/erl_docgen.app.src b/lib/erl_docgen/src/erl_docgen.app.src index 1720464b6d..daad172106 100644 --- a/lib/erl_docgen/src/erl_docgen.app.src +++ b/lib/erl_docgen/src/erl_docgen.app.src @@ -1,7 +1,9 @@ {application, erl_docgen, [{description, "Misc tools for building documentation"}, {vsn, "%VSN%"}, - {modules, [otp_specs + {modules, [docgen_otp_specs, + docgen_edoc_xml_cb, + docgen_xmerl_xml_cb ] }, {registered,[]}, diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk index 79c8c570bf..dbd7e017b0 100644 --- a/lib/erl_docgen/vsn.mk +++ b/lib/erl_docgen/vsn.mk @@ -1,2 +1,2 @@ -ERL_DOCGEN_VSN = 0.2.6 +ERL_DOCGEN_VSN = 0.3 diff --git a/lib/erl_interface/doc/src/make.dep b/lib/erl_interface/doc/src/make.dep deleted file mode 100644 index 3f43cf64fe..0000000000 --- a/lib/erl_interface/doc/src/make.dep +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin//docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex ei.tex ei_connect.tex ei_users_guide.tex \ - erl_call.tex erl_connect.tex erl_error.tex \ - erl_eterm.tex erl_format.tex erl_global.tex \ - erl_malloc.tex erl_marshal.tex part_ei.tex \ - ref_man.tex ref_man_ei.tex ref_man_erl_interface.tex \ - registry.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml ref_man_ei.xml ref_man_erl_interface.xml - diff --git a/lib/eunit/doc/src/make.dep b/lib/eunit/doc/src/make.dep deleted file mode 100644 index d68f888403..0000000000 --- a/lib/eunit/doc/src/make.dep +++ /dev/null @@ -1,19 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex chapter.tex eunit.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/gs/doc/src/make.dep b/lib/gs/doc/src/make.dep deleted file mode 100644 index b33ed3b2de..0000000000 --- a/lib/gs/doc/src/make.dep +++ /dev/null @@ -1,58 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex gs.tex gs_chapter1.tex gs_chapter2.tex \ - gs_chapter3.tex gs_chapter4.tex gs_chapter5.tex \ - gs_chapter6.tex gs_chapter7.tex gs_chapter8.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -gs_chapter2.tex: examples/ex1.erl examples/ex2.erl - -gs_chapter4.tex: examples/ex3.erl examples/ex4.erl examples/ex5.erl \ - examples/ex6.erl - -gs_chapter5.tex: examples/ex15.erl - -gs_chapter6.tex: examples/ex16.erl - -gs_chapter7.tex: examples/ex17.erl - -gs_chapter8.tex: examples/ex10.erl examples/ex11.erl examples/ex12.erl \ - examples/ex13.erl examples/ex14.erl examples/ex7.erl \ - examples/ex8.erl examples/ex9.erl - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: pics/gs1-1-image-1.ps pics/gs1-1-image-2.ps \ - pics/gs1-1-image-3.ps - -book.dvi: pics/ex1.ps pics/gs1-1-image-4.ps - -book.dvi: pics/ex15.ps - -book.dvi: pics/ex16.ps - -book.dvi: pics/packer1.ps pics/packer2.ps - -book.dvi: pics/arc.ps pics/buttons.ps pics/ex10.ps pics/ex11.ps \ - pics/ex12.ps pics/ex13.ps pics/ex14.ps pics/ex8.ps \ - pics/ex9.ps pics/image.ps pics/line.ps pics/oval.ps \ - pics/polygon.ps pics/rectangle.ps pics/text.ps \ - pics/window.ps - diff --git a/lib/hipe/doc/src/make.dep b/lib/hipe/doc/src/make.dep deleted file mode 100644 index d5f5844c21..0000000000 --- a/lib/hipe/doc/src/make.dep +++ /dev/null @@ -1,13 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex - diff --git a/lib/hipe/icode/hipe_icode_pp.erl b/lib/hipe/icode/hipe_icode_pp.erl index 575bbfe43d..575bbfe43d 100755..100644 --- a/lib/hipe/icode/hipe_icode_pp.erl +++ b/lib/hipe/icode/hipe_icode_pp.erl diff --git a/lib/hipe/icode/hipe_icode_ssa.erl b/lib/hipe/icode/hipe_icode_ssa.erl index 719d5d8f45..719d5d8f45 100755..100644 --- a/lib/hipe/icode/hipe_icode_ssa.erl +++ b/lib/hipe/icode/hipe_icode_ssa.erl diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile index 55d20af8af..690045b978 100644 --- a/lib/hipe/rtl/Makefile +++ b/lib/hipe/rtl/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2010. All Rights Reserved. +# Copyright Ericsson AB 2001-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -108,10 +108,30 @@ release_spec: opt release_docs_spec: -HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals +ifeq ($(TYPE),debug) +TYPE_STR=.debug +else +TYPE_STR= +endif + +ifeq ($(FLAVOR),smp) +FLAVOR_STR=.smp +else +FLAVOR_STR= +endif + +ifeq ($(XCOMP),yes) +MKLIT_FLAGS= -x +else +MKLIT_FLAGS= +endif + + +HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals$(TYPE_STR)$(FLAVOR_STR) + hipe_literals.hrl: $(HIPE_MKLITERALS) - $(HIPE_MKLITERALS) -e > hipe_literals.hrl + $(HIPE_MKLITERALS) $(MKLIT_FLAGS) -e > hipe_literals.hrl # Need to generate hipe.hrl from one and only one target in one and only # one makefile; otherwise, clearmake will force rebuilds of hipe over and diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl index 29e9c8c8fe..4bf4eb6bd7 100644 --- a/lib/hipe/rtl/hipe_rtl.erl +++ b/lib/hipe/rtl/hipe_rtl.erl @@ -781,8 +781,11 @@ fstore_src_update(F, NewSrc) -> F#fstore{src=NewSrc}. %% fp %% + mk_fp(Dst, Src1, Op, Src2) -> - #fp{dst=Dst, src1=Src1, op=Op, src2=Src2}. + [#fp{dst=Dst, src1=Src1, op=Op, src2=Src2} + | hipe_rtl_arch:mk_fp_check_result(Dst)]. + fp_dst(#fp{dst=Dst}) -> Dst. fp_dst_update(Fp, NewDst) -> Fp#fp{dst=NewDst}. fp_src1(#fp{src1=Src1}) -> Src1. diff --git a/lib/hipe/rtl/hipe_rtl_arch.erl b/lib/hipe/rtl/hipe_rtl_arch.erl index 22cda57a3a..99eb80f3d1 100644 --- a/lib/hipe/rtl/hipe_rtl_arch.erl +++ b/lib/hipe/rtl/hipe_rtl_arch.erl @@ -65,7 +65,8 @@ %% alignment/0, nr_of_return_regs/0, log2_word_size/0, - word_size/0 + word_size/0, + mk_fp_check_result/1 ]). -include("hipe_literals.hrl"). @@ -558,6 +559,12 @@ eval_cond_bits(Cond, N, Z, V, C) -> %%---------------------------------------------------------------------- fwait() -> + case ?ERTS_NO_FPE_SIGNALS of + 1 -> []; + 0 -> fwait_real() + end. + +fwait_real() -> case get(hipe_target_arch) of x86 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)]; amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)]; @@ -573,6 +580,12 @@ fwait() -> %% Returns RTL code to restore the FPU after a floating-point exception. %% @end handle_fp_exception() -> + case ?ERTS_NO_FPE_SIGNALS of + 1 -> []; + 0 -> handle_real_fp_exception() + end. + +handle_real_fp_exception() -> case get(hipe_target_arch) of x86 -> ContLbl = hipe_rtl:mk_new_label(), @@ -655,3 +668,15 @@ nr_of_return_regs() -> 1 %% hipe_amd64_registers:nr_rets(); end. + + +mk_fp_check_result(Result) -> + case ?ERTS_NO_FPE_SIGNALS of + 0 -> + []; + 1 -> + [hipe_rtl:mk_fstore(proc_pointer(), + hipe_rtl:mk_imm(?P_FLOAT_RESULT), + Result), + hipe_rtl:mk_call([], emulate_fpe, [], [], [], not_remote)] + end. diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl index 9224623c8b..262aedb409 100644 --- a/lib/hipe/rtl/hipe_rtl_lcm.erl +++ b/lib/hipe/rtl/hipe_rtl_lcm.erl @@ -486,7 +486,7 @@ lcm_precalc(CFG, Options) -> ?option_time(NodeInfo2 = calc_down_exp(CFG, ExprMap, NodeInfo1, Labels), "RTL LCM calc_down_exp", Options), ?option_time(NodeInfo3 = calc_killed_expr(CFG, NodeInfo2, UseMap, AllExpr, - Labels), + IdMap, Labels), "RTL LCM calc_killed_exp", Options), ?option_time(NodeInfo4 = calc_avail(CFG, NodeInfo3), "RTL LCM calc_avail", Options), @@ -815,19 +815,19 @@ exp_kill_expr(Instr, [CheckedExpr|Exprs]) -> %%============================================================================= %% Calculates the killed expression sets for all given labels. -calc_killed_expr(_, NodeInfo, _, _, []) -> +calc_killed_expr(_, NodeInfo, _, _, _, []) -> NodeInfo; -calc_killed_expr(CFG, NodeInfo, UseMap, AllExpr, [Label|Labels]) -> +calc_killed_expr(CFG, NodeInfo, UseMap, AllExpr, IdMap, [Label|Labels]) -> Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)), - KilledExprs = calc_killed_expr_bb(Code, UseMap, AllExpr, ?SETS:new()), + KilledExprs = calc_killed_expr_bb(Code, UseMap, AllExpr, IdMap, ?SETS:new()), NewNodeInfo = set_killed_expr(NodeInfo, Label, KilledExprs), - calc_killed_expr(CFG, NewNodeInfo, UseMap, AllExpr, Labels). + calc_killed_expr(CFG, NewNodeInfo, UseMap, AllExpr, IdMap, Labels). %%============================================================================= %% Calculates the killed expressions set for one basic block. -calc_killed_expr_bb([], _UseMap, _AllExpr, KilledExprs) -> +calc_killed_expr_bb([], _UseMap, _AllExpr, _IdMap, KilledExprs) -> KilledExprs; -calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) -> +calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, IdMap, KilledExprs) -> %% Calls, gctests and stores potentially clobber everything case Instr of #call{} -> AllExpr; @@ -837,7 +837,8 @@ calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) -> %% Kill all float expressions %% FIXME: Make separate function is_fp_expr ?SETS:from_list - (lists:foldl(fun(Expr, Fexprs) -> + (lists:foldl(fun(ExprId, Fexprs) -> + Expr = expr_id_map_get_expr(IdMap, ExprId), [Define|_] = hipe_rtl:defines(Expr), case hipe_rtl:is_fpreg(Define) of true -> @@ -849,10 +850,10 @@ calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) -> _ -> case hipe_rtl:defines(Instr) of [] -> - calc_killed_expr_bb(Instrs, UseMap, AllExpr, KilledExprs); + calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap, KilledExprs); [Define|_] -> NewKilledExprs = use_map_get_expr_uses(UseMap, Define), - calc_killed_expr_bb(Instrs, UseMap, AllExpr, + calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap, ?SETS:union(NewKilledExprs, KilledExprs)) end end. diff --git a/lib/hipe/util/hipe_dot.erl b/lib/hipe/util/hipe_dot.erl index d6ef801c88..d6ef801c88 100755..100644 --- a/lib/hipe/util/hipe_dot.erl +++ b/lib/hipe/util/hipe_dot.erl diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile index f255183e1f..1e93578cb1 100644 --- a/lib/ic/doc/src/Makefile +++ b/lib/ic/doc/src/Makefile @@ -26,13 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include ../../vsn.mk VSN=$(IC_VSN) APPLICATION=ic -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif # ---------------------------------------------------- # Java specific @@ -96,32 +89,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - JAVA_SOURCE_FILES = \ Holder.java \ BooleanHolder.java \ @@ -209,8 +180,6 @@ JAVADOCFLAGS = \ $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - ifneq (,$(JAVA)) docs: pdf html man $(JAVADOC_GENERATED_FILES) else @@ -229,34 +198,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html $(JAVADOC_GENERATED_FILES) gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - rm -rf $(JAVA_OUT_DIR) - rm -f JAVADOC-GENERATED - -endif - $(JAVADOC_GENERATED_FILES): JAVADOC-GENERATED JAVADOC-GENERATED: $(JAVA_SOURCE_FILES:%=$(JAVA_SOURCE_DIR)/%) @@ -278,8 +219,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -289,46 +228,4 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) -ifneq (,$(JAVA)) - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/resources - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp - $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic - $(INSTALL_DATA) $(JAVADOC_INDEX_HTML_FILES) \ - $(RELSYSDIR)/doc/html/java - $(INSTALL_DATA) $(JD_GIF_FILES) \ - $(RELSYSDIR)/doc/html/java/resources - $(INSTALL_DATA) $(JAVADOC_PACK_HTML_FILES) \ - $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic -endif - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif - - release_spec: - - diff --git a/lib/ic/doc/src/make.dep b/lib/ic/doc/src/make.dep deleted file mode 100644 index 64694ee85a..0000000000 --- a/lib/ic/doc/src/make.dep +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex c-part.tex ch_basic_idl.tex ch_c_client.tex \ - ch_c_corba_env.tex ch_c_mapping.tex ch_c_server.tex \ - ch_erl_genserv.tex ch_erl_plain.tex ch_ic_protocol.tex \ - ch_introduction.tex ch_java.tex erl-part.tex \ - ic.tex ic_c_protocol.tex ic_clib.tex java-part.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/inets/doc/archive/rfc3986.txt b/lib/inets/doc/archive/rfc3986.txt new file mode 100644 index 0000000000..c56ed4eb70 --- /dev/null +++ b/lib/inets/doc/archive/rfc3986.txt @@ -0,0 +1,3419 @@ + + + + + + +Network Working Group T. Berners-Lee +Request for Comments: 3986 W3C/MIT +STD: 66 R. Fielding +Updates: 1738 Day Software +Obsoletes: 2732, 2396, 1808 L. Masinter +Category: Standards Track Adobe Systems + January 2005 + + + Uniform Resource Identifier (URI): Generic Syntax + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + A Uniform Resource Identifier (URI) is a compact sequence of + characters that identifies an abstract or physical resource. This + specification defines the generic URI syntax and a process for + resolving URI references that might be in relative form, along with + guidelines and security considerations for the use of URIs on the + Internet. The URI syntax defines a grammar that is a superset of all + valid URIs, allowing an implementation to parse the common components + of a URI reference without knowing the scheme-specific requirements + of every possible identifier. This specification does not define a + generative grammar for URIs; that task is performed by the individual + specifications of each URI scheme. + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 1] + +RFC 3986 URI Generic Syntax January 2005 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Overview of URIs . . . . . . . . . . . . . . . . . . . . 4 + 1.1.1. Generic Syntax . . . . . . . . . . . . . . . . . 6 + 1.1.2. Examples . . . . . . . . . . . . . . . . . . . . 7 + 1.1.3. URI, URL, and URN . . . . . . . . . . . . . . . 7 + 1.2. Design Considerations . . . . . . . . . . . . . . . . . 8 + 1.2.1. Transcription . . . . . . . . . . . . . . . . . 8 + 1.2.2. Separating Identification from Interaction . . . 9 + 1.2.3. Hierarchical Identifiers . . . . . . . . . . . . 10 + 1.3. Syntax Notation . . . . . . . . . . . . . . . . . . . . 11 + 2. Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 2.1. Percent-Encoding . . . . . . . . . . . . . . . . . . . . 12 + 2.2. Reserved Characters . . . . . . . . . . . . . . . . . . 12 + 2.3. Unreserved Characters . . . . . . . . . . . . . . . . . 13 + 2.4. When to Encode or Decode . . . . . . . . . . . . . . . . 14 + 2.5. Identifying Data . . . . . . . . . . . . . . . . . . . . 14 + 3. Syntax Components . . . . . . . . . . . . . . . . . . . . . . 16 + 3.1. Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 17 + 3.2. Authority . . . . . . . . . . . . . . . . . . . . . . . 17 + 3.2.1. User Information . . . . . . . . . . . . . . . . 18 + 3.2.2. Host . . . . . . . . . . . . . . . . . . . . . . 18 + 3.2.3. Port . . . . . . . . . . . . . . . . . . . . . . 22 + 3.3. Path . . . . . . . . . . . . . . . . . . . . . . . . . . 22 + 3.4. Query . . . . . . . . . . . . . . . . . . . . . . . . . 23 + 3.5. Fragment . . . . . . . . . . . . . . . . . . . . . . . . 24 + 4. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 + 4.1. URI Reference . . . . . . . . . . . . . . . . . . . . . 25 + 4.2. Relative Reference . . . . . . . . . . . . . . . . . . . 26 + 4.3. Absolute URI . . . . . . . . . . . . . . . . . . . . . . 27 + 4.4. Same-Document Reference . . . . . . . . . . . . . . . . 27 + 4.5. Suffix Reference . . . . . . . . . . . . . . . . . . . . 27 + 5. Reference Resolution . . . . . . . . . . . . . . . . . . . . . 28 + 5.1. Establishing a Base URI . . . . . . . . . . . . . . . . 28 + 5.1.1. Base URI Embedded in Content . . . . . . . . . . 29 + 5.1.2. Base URI from the Encapsulating Entity . . . . . 29 + 5.1.3. Base URI from the Retrieval URI . . . . . . . . 30 + 5.1.4. Default Base URI . . . . . . . . . . . . . . . . 30 + 5.2. Relative Resolution . . . . . . . . . . . . . . . . . . 30 + 5.2.1. Pre-parse the Base URI . . . . . . . . . . . . . 31 + 5.2.2. Transform References . . . . . . . . . . . . . . 31 + 5.2.3. Merge Paths . . . . . . . . . . . . . . . . . . 32 + 5.2.4. Remove Dot Segments . . . . . . . . . . . . . . 33 + 5.3. Component Recomposition . . . . . . . . . . . . . . . . 35 + 5.4. Reference Resolution Examples . . . . . . . . . . . . . 35 + 5.4.1. Normal Examples . . . . . . . . . . . . . . . . 36 + 5.4.2. Abnormal Examples . . . . . . . . . . . . . . . 36 + + + +Berners-Lee, et al. Standards Track [Page 2] + +RFC 3986 URI Generic Syntax January 2005 + + + 6. Normalization and Comparison . . . . . . . . . . . . . . . . . 38 + 6.1. Equivalence . . . . . . . . . . . . . . . . . . . . . . 38 + 6.2. Comparison Ladder . . . . . . . . . . . . . . . . . . . 39 + 6.2.1. Simple String Comparison . . . . . . . . . . . . 39 + 6.2.2. Syntax-Based Normalization . . . . . . . . . . . 40 + 6.2.3. Scheme-Based Normalization . . . . . . . . . . . 41 + 6.2.4. Protocol-Based Normalization . . . . . . . . . . 42 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43 + 7.1. Reliability and Consistency . . . . . . . . . . . . . . 43 + 7.2. Malicious Construction . . . . . . . . . . . . . . . . . 43 + 7.3. Back-End Transcoding . . . . . . . . . . . . . . . . . . 44 + 7.4. Rare IP Address Formats . . . . . . . . . . . . . . . . 45 + 7.5. Sensitive Information . . . . . . . . . . . . . . . . . 45 + 7.6. Semantic Attacks . . . . . . . . . . . . . . . . . . . . 45 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 46 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 46 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 46 + 10.1. Normative References . . . . . . . . . . . . . . . . . . 46 + 10.2. Informative References . . . . . . . . . . . . . . . . . 47 + A. Collected ABNF for URI . . . . . . . . . . . . . . . . . . . . 49 + B. Parsing a URI Reference with a Regular Expression . . . . . . 50 + C. Delimiting a URI in Context . . . . . . . . . . . . . . . . . 51 + D. Changes from RFC 2396 . . . . . . . . . . . . . . . . . . . . 53 + D.1. Additions . . . . . . . . . . . . . . . . . . . . . . . 53 + D.2. Modifications . . . . . . . . . . . . . . . . . . . . . 53 + Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 60 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 61 + + + + + + + + + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 3] + +RFC 3986 URI Generic Syntax January 2005 + + +1. Introduction + + A Uniform Resource Identifier (URI) provides a simple and extensible + means for identifying a resource. This specification of URI syntax + and semantics is derived from concepts introduced by the World Wide + Web global information initiative, whose use of these identifiers + dates from 1990 and is described in "Universal Resource Identifiers + in WWW" [RFC1630]. The syntax is designed to meet the + recommendations laid out in "Functional Recommendations for Internet + Resource Locators" [RFC1736] and "Functional Requirements for Uniform + Resource Names" [RFC1737]. + + This document obsoletes [RFC2396], which merged "Uniform Resource + Locators" [RFC1738] and "Relative Uniform Resource Locators" + [RFC1808] in order to define a single, generic syntax for all URIs. + It obsoletes [RFC2732], which introduced syntax for an IPv6 address. + It excludes portions of RFC 1738 that defined the specific syntax of + individual URI schemes; those portions will be updated as separate + documents. The process for registration of new URI schemes is + defined separately by [BCP35]. Advice for designers of new URI + schemes can be found in [RFC2718]. All significant changes from RFC + 2396 are noted in Appendix D. + + This specification uses the terms "character" and "coded character + set" in accordance with the definitions provided in [BCP19], and + "character encoding" in place of what [BCP19] refers to as a + "charset". + +1.1. Overview of URIs + + URIs are characterized as follows: + + Uniform + + Uniformity provides several benefits. It allows different types + of resource identifiers to be used in the same context, even when + the mechanisms used to access those resources may differ. It + allows uniform semantic interpretation of common syntactic + conventions across different types of resource identifiers. It + allows introduction of new types of resource identifiers without + interfering with the way that existing identifiers are used. It + allows the identifiers to be reused in many different contexts, + thus permitting new applications or protocols to leverage a pre- + existing, large, and widely used set of resource identifiers. + + + + + + + +Berners-Lee, et al. Standards Track [Page 4] + +RFC 3986 URI Generic Syntax January 2005 + + + Resource + + This specification does not limit the scope of what might be a + resource; rather, the term "resource" is used in a general sense + for whatever might be identified by a URI. Familiar examples + include an electronic document, an image, a source of information + with a consistent purpose (e.g., "today's weather report for Los + Angeles"), a service (e.g., an HTTP-to-SMS gateway), and a + collection of other resources. A resource is not necessarily + accessible via the Internet; e.g., human beings, corporations, and + bound books in a library can also be resources. Likewise, + abstract concepts can be resources, such as the operators and + operands of a mathematical equation, the types of a relationship + (e.g., "parent" or "employee"), or numeric values (e.g., zero, + one, and infinity). + + Identifier + + An identifier embodies the information required to distinguish + what is being identified from all other things within its scope of + identification. Our use of the terms "identify" and "identifying" + refer to this purpose of distinguishing one resource from all + other resources, regardless of how that purpose is accomplished + (e.g., by name, address, or context). These terms should not be + mistaken as an assumption that an identifier defines or embodies + the identity of what is referenced, though that may be the case + for some identifiers. Nor should it be assumed that a system + using URIs will access the resource identified: in many cases, + URIs are used to denote resources without any intention that they + be accessed. Likewise, the "one" resource identified might not be + singular in nature (e.g., a resource might be a named set or a + mapping that varies over time). + + A URI is an identifier consisting of a sequence of characters + matching the syntax rule named <URI> in Section 3. It enables + uniform identification of resources via a separately defined + extensible set of naming schemes (Section 3.1). How that + identification is accomplished, assigned, or enabled is delegated to + each scheme specification. + + This specification does not place any limits on the nature of a + resource, the reasons why an application might seek to refer to a + resource, or the kinds of systems that might use URIs for the sake of + identifying resources. This specification does not require that a + URI persists in identifying the same resource over time, though that + is a common goal of all URI schemes. Nevertheless, nothing in this + + + + + +Berners-Lee, et al. Standards Track [Page 5] + +RFC 3986 URI Generic Syntax January 2005 + + + specification prevents an application from limiting itself to + particular types of resources, or to a subset of URIs that maintains + characteristics desired by that application. + + URIs have a global scope and are interpreted consistently regardless + of context, though the result of that interpretation may be in + relation to the end-user's context. For example, "http://localhost/" + has the same interpretation for every user of that reference, even + though the network interface corresponding to "localhost" may be + different for each end-user: interpretation is independent of access. + However, an action made on the basis of that reference will take + place in relation to the end-user's context, which implies that an + action intended to refer to a globally unique thing must use a URI + that distinguishes that resource from all other things. URIs that + identify in relation to the end-user's local context should only be + used when the context itself is a defining aspect of the resource, + such as when an on-line help manual refers to a file on the end- + user's file system (e.g., "file:///etc/hosts"). + +1.1.1. Generic Syntax + + Each URI begins with a scheme name, as defined in Section 3.1, that + refers to a specification for assigning identifiers within that + scheme. As such, the URI syntax is a federated and extensible naming + system wherein each scheme's specification may further restrict the + syntax and semantics of identifiers using that scheme. + + This specification defines those elements of the URI syntax that are + required of all URI schemes or are common to many URI schemes. It + thus defines the syntax and semantics needed to implement a scheme- + independent parsing mechanism for URI references, by which the + scheme-dependent handling of a URI can be postponed until the + scheme-dependent semantics are needed. Likewise, protocols and data + formats that make use of URI references can refer to this + specification as a definition for the range of syntax allowed for all + URIs, including those schemes that have yet to be defined. This + decouples the evolution of identification schemes from the evolution + of protocols, data formats, and implementations that make use of + URIs. + + A parser of the generic URI syntax can parse any URI reference into + its major components. Once the scheme is determined, further + scheme-specific parsing can be performed on the components. In other + words, the URI generic syntax is a superset of the syntax of all URI + schemes. + + + + + + +Berners-Lee, et al. Standards Track [Page 6] + +RFC 3986 URI Generic Syntax January 2005 + + +1.1.2. Examples + + The following example URIs illustrate several URI schemes and + variations in their common syntax components: + + ftp://ftp.is.co.za/rfc/rfc1808.txt + + http://www.ietf.org/rfc/rfc2396.txt + + ldap://[2001:db8::7]/c=GB?objectClass?one + + mailto:[email protected] + + news:comp.infosystems.www.servers.unix + + tel:+1-816-555-1212 + + telnet://192.0.2.16:80/ + + urn:oasis:names:specification:docbook:dtd:xml:4.1.2 + + +1.1.3. URI, URL, and URN + + A URI can be further classified as a locator, a name, or both. The + term "Uniform Resource Locator" (URL) refers to the subset of URIs + that, in addition to identifying a resource, provide a means of + locating the resource by describing its primary access mechanism + (e.g., its network "location"). The term "Uniform Resource Name" + (URN) has been used historically to refer to both URIs under the + "urn" scheme [RFC2141], which are required to remain globally unique + and persistent even when the resource ceases to exist or becomes + unavailable, and to any other URI with the properties of a name. + + An individual scheme does not have to be classified as being just one + of "name" or "locator". Instances of URIs from any given scheme may + have the characteristics of names or locators or both, often + depending on the persistence and care in the assignment of + identifiers by the naming authority, rather than on any quality of + the scheme. Future specifications and related documentation should + use the general term "URI" rather than the more restrictive terms + "URL" and "URN" [RFC3305]. + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 7] + +RFC 3986 URI Generic Syntax January 2005 + + +1.2. Design Considerations + +1.2.1. Transcription + + The URI syntax has been designed with global transcription as one of + its main considerations. A URI is a sequence of characters from a + very limited set: the letters of the basic Latin alphabet, digits, + and a few special characters. A URI may be represented in a variety + of ways; e.g., ink on paper, pixels on a screen, or a sequence of + character encoding octets. The interpretation of a URI depends only + on the characters used and not on how those characters are + represented in a network protocol. + + The goal of transcription can be described by a simple scenario. + Imagine two colleagues, Sam and Kim, sitting in a pub at an + international conference and exchanging research ideas. Sam asks Kim + for a location to get more information, so Kim writes the URI for the + research site on a napkin. Upon returning home, Sam takes out the + napkin and types the URI into a computer, which then retrieves the + information to which Kim referred. + + There are several design considerations revealed by the scenario: + + o A URI is a sequence of characters that is not always represented + as a sequence of octets. + + o A URI might be transcribed from a non-network source and thus + should consist of characters that are most likely able to be + entered into a computer, within the constraints imposed by + keyboards (and related input devices) across languages and + locales. + + o A URI often has to be remembered by people, and it is easier for + people to remember a URI when it consists of meaningful or + familiar components. + + These design considerations are not always in alignment. For + example, it is often the case that the most meaningful name for a URI + component would require characters that cannot be typed into some + systems. The ability to transcribe a resource identifier from one + medium to another has been considered more important than having a + URI consist of the most meaningful of components. + + In local or regional contexts and with improving technology, users + might benefit from being able to use a wider range of characters; + such use is not defined by this specification. Percent-encoded + octets (Section 2.1) may be used within a URI to represent characters + outside the range of the US-ASCII coded character set if this + + + +Berners-Lee, et al. Standards Track [Page 8] + +RFC 3986 URI Generic Syntax January 2005 + + + representation is allowed by the scheme or by the protocol element in + which the URI is referenced. Such a definition should specify the + character encoding used to map those characters to octets prior to + being percent-encoded for the URI. + +1.2.2. Separating Identification from Interaction + + A common misunderstanding of URIs is that they are only used to refer + to accessible resources. The URI itself only provides + identification; access to the resource is neither guaranteed nor + implied by the presence of a URI. Instead, any operation associated + with a URI reference is defined by the protocol element, data format + attribute, or natural language text in which it appears. + + Given a URI, a system may attempt to perform a variety of operations + on the resource, as might be characterized by words such as "access", + "update", "replace", or "find attributes". Such operations are + defined by the protocols that make use of URIs, not by this + specification. However, we do use a few general terms for describing + common operations on URIs. URI "resolution" is the process of + determining an access mechanism and the appropriate parameters + necessary to dereference a URI; this resolution may require several + iterations. To use that access mechanism to perform an action on the + URI's resource is to "dereference" the URI. + + When URIs are used within information retrieval systems to identify + sources of information, the most common form of URI dereference is + "retrieval": making use of a URI in order to retrieve a + representation of its associated resource. A "representation" is a + sequence of octets, along with representation metadata describing + those octets, that constitutes a record of the state of the resource + at the time when the representation is generated. Retrieval is + achieved by a process that might include using the URI as a cache key + to check for a locally cached representation, resolution of the URI + to determine an appropriate access mechanism (if any), and + dereference of the URI for the sake of applying a retrieval + operation. Depending on the protocols used to perform the retrieval, + additional information might be supplied about the resource (resource + metadata) and its relation to other resources. + + URI references in information retrieval systems are designed to be + late-binding: the result of an access is generally determined when it + is accessed and may vary over time or due to other aspects of the + interaction. These references are created in order to be used in the + future: what is being identified is not some specific result that was + obtained in the past, but rather some characteristic that is expected + to be true for future results. In such cases, the resource referred + to by the URI is actually a sameness of characteristics as observed + + + +Berners-Lee, et al. Standards Track [Page 9] + +RFC 3986 URI Generic Syntax January 2005 + + + over time, perhaps elucidated by additional comments or assertions + made by the resource provider. + + Although many URI schemes are named after protocols, this does not + imply that use of these URIs will result in access to the resource + via the named protocol. URIs are often used simply for the sake of + identification. Even when a URI is used to retrieve a representation + of a resource, that access might be through gateways, proxies, + caches, and name resolution services that are independent of the + protocol associated with the scheme name. The resolution of some + URIs may require the use of more than one protocol (e.g., both DNS + and HTTP are typically used to access an "http" URI's origin server + when a representation isn't found in a local cache). + +1.2.3. Hierarchical Identifiers + + The URI syntax is organized hierarchically, with components listed in + order of decreasing significance from left to right. For some URI + schemes, the visible hierarchy is limited to the scheme itself: + everything after the scheme component delimiter (":") is considered + opaque to URI processing. Other URI schemes make the hierarchy + explicit and visible to generic parsing algorithms. + + The generic syntax uses the slash ("/"), question mark ("?"), and + number sign ("#") characters to delimit components that are + significant to the generic parser's hierarchical interpretation of an + identifier. In addition to aiding the readability of such + identifiers through the consistent use of familiar syntax, this + uniform representation of hierarchy across naming schemes allows + scheme-independent references to be made relative to that hierarchy. + + It is often the case that a group or "tree" of documents has been + constructed to serve a common purpose, wherein the vast majority of + URI references in these documents point to resources within the tree + rather than outside it. Similarly, documents located at a particular + site are much more likely to refer to other resources at that site + than to resources at remote sites. Relative referencing of URIs + allows document trees to be partially independent of their location + and access scheme. For instance, it is possible for a single set of + hypertext documents to be simultaneously accessible and traversable + via each of the "file", "http", and "ftp" schemes if the documents + refer to each other with relative references. Furthermore, such + document trees can be moved, as a whole, without changing any of the + relative references. + + A relative reference (Section 4.2) refers to a resource by describing + the difference within a hierarchical name space between the reference + context and the target URI. The reference resolution algorithm, + + + +Berners-Lee, et al. Standards Track [Page 10] + +RFC 3986 URI Generic Syntax January 2005 + + + presented in Section 5, defines how such a reference is transformed + to the target URI. As relative references can only be used within + the context of a hierarchical URI, designers of new URI schemes + should use a syntax consistent with the generic syntax's hierarchical + components unless there are compelling reasons to forbid relative + referencing within that scheme. + + NOTE: Previous specifications used the terms "partial URI" and + "relative URI" to denote a relative reference to a URI. As some + readers misunderstood those terms to mean that relative URIs are a + subset of URIs rather than a method of referencing URIs, this + specification simply refers to them as relative references. + + All URI references are parsed by generic syntax parsers when used. + However, because hierarchical processing has no effect on an absolute + URI used in a reference unless it contains one or more dot-segments + (complete path segments of "." or "..", as described in Section 3.3), + URI scheme specifications can define opaque identifiers by + disallowing use of slash characters, question mark characters, and + the URIs "scheme:." and "scheme:..". + +1.3. Syntax Notation + + This specification uses the Augmented Backus-Naur Form (ABNF) + notation of [RFC2234], including the following core ABNF syntax rules + defined by that specification: ALPHA (letters), CR (carriage return), + DIGIT (decimal digits), DQUOTE (double quote), HEXDIG (hexadecimal + digits), LF (line feed), and SP (space). The complete URI syntax is + collected in Appendix A. + +2. Characters + + The URI syntax provides a method of encoding data, presumably for the + sake of identifying a resource, as a sequence of characters. The URI + characters are, in turn, frequently encoded as octets for transport + or presentation. This specification does not mandate any particular + character encoding for mapping between URI characters and the octets + used to store or transmit those characters. When a URI appears in a + protocol element, the character encoding is defined by that protocol; + without such a definition, a URI is assumed to be in the same + character encoding as the surrounding text. + + The ABNF notation defines its terminal values to be non-negative + integers (codepoints) based on the US-ASCII coded character set + [ASCII]. Because a URI is a sequence of characters, we must invert + that relation in order to understand the URI syntax. Therefore, the + + + + + +Berners-Lee, et al. Standards Track [Page 11] + +RFC 3986 URI Generic Syntax January 2005 + + + integer values used by the ABNF must be mapped back to their + corresponding characters via US-ASCII in order to complete the syntax + rules. + + A URI is composed from a limited set of characters consisting of + digits, letters, and a few graphic symbols. A reserved subset of + those characters may be used to delimit syntax components within a + URI while the remaining characters, including both the unreserved set + and those reserved characters not acting as delimiters, define each + component's identifying data. + +2.1. Percent-Encoding + + A percent-encoding mechanism is used to represent a data octet in a + component when that octet's corresponding character is outside the + allowed set or is being used as a delimiter of, or within, the + component. A percent-encoded octet is encoded as a character + triplet, consisting of the percent character "%" followed by the two + hexadecimal digits representing that octet's numeric value. For + example, "%20" is the percent-encoding for the binary octet + "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space + character (SP). Section 2.4 describes when percent-encoding and + decoding is applied. + + pct-encoded = "%" HEXDIG HEXDIG + + The uppercase hexadecimal digits 'A' through 'F' are equivalent to + the lowercase digits 'a' through 'f', respectively. If two URIs + differ only in the case of hexadecimal digits used in percent-encoded + octets, they are equivalent. For consistency, URI producers and + normalizers should use uppercase hexadecimal digits for all percent- + encodings. + +2.2. Reserved Characters + + URIs include components and subcomponents that are delimited by + characters in the "reserved" set. These characters are called + "reserved" because they may (or may not) be defined as delimiters by + the generic syntax, by each scheme-specific syntax, or by the + implementation-specific syntax of a URI's dereferencing algorithm. + If data for a URI component would conflict with a reserved + character's purpose as a delimiter, then the conflicting data must be + percent-encoded before the URI is formed. + + + + + + + + +Berners-Lee, et al. Standards Track [Page 12] + +RFC 3986 URI Generic Syntax January 2005 + + + reserved = gen-delims / sub-delims + + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + + The purpose of reserved characters is to provide a set of delimiting + characters that are distinguishable from other data within a URI. + URIs that differ in the replacement of a reserved character with its + corresponding percent-encoded octet are not equivalent. Percent- + encoding a reserved character, or decoding a percent-encoded octet + that corresponds to a reserved character, will change how the URI is + interpreted by most applications. Thus, characters in the reserved + set are protected from normalization and are therefore safe to be + used by scheme-specific and producer-specific algorithms for + delimiting data subcomponents within a URI. + + A subset of the reserved characters (gen-delims) is used as + delimiters of the generic URI components described in Section 3. A + component's ABNF syntax rule will not use the reserved or gen-delims + rule names directly; instead, each syntax rule lists the characters + allowed within that component (i.e., not delimiting it), and any of + those characters that are also in the reserved set are "reserved" for + use as subcomponent delimiters within the component. Only the most + common subcomponents are defined by this specification; other + subcomponents may be defined by a URI scheme's specification, or by + the implementation-specific syntax of a URI's dereferencing + algorithm, provided that such subcomponents are delimited by + characters in the reserved set allowed within that component. + + URI producing applications should percent-encode data octets that + correspond to characters in the reserved set unless these characters + are specifically allowed by the URI scheme to represent data in that + component. If a reserved character is found in a URI component and + no delimiting role is known for that character, then it must be + interpreted as representing the data octet corresponding to that + character's encoding in US-ASCII. + +2.3. Unreserved Characters + + Characters that are allowed in a URI but do not have a reserved + purpose are called unreserved. These include uppercase and lowercase + letters, decimal digits, hyphen, period, underscore, and tilde. + + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + + + + + +Berners-Lee, et al. Standards Track [Page 13] + +RFC 3986 URI Generic Syntax January 2005 + + + URIs that differ in the replacement of an unreserved character with + its corresponding percent-encoded US-ASCII octet are equivalent: they + identify the same resource. However, URI comparison implementations + do not always perform normalization prior to comparison (see Section + 6). For consistency, percent-encoded octets in the ranges of ALPHA + (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), + underscore (%5F), or tilde (%7E) should not be created by URI + producers and, when found in a URI, should be decoded to their + corresponding unreserved characters by URI normalizers. + +2.4. When to Encode or Decode + + Under normal circumstances, the only time when octets within a URI + are percent-encoded is during the process of producing the URI from + its component parts. This is when an implementation determines which + of the reserved characters are to be used as subcomponent delimiters + and which can be safely used as data. Once produced, a URI is always + in its percent-encoded form. + + When a URI is dereferenced, the components and subcomponents + significant to the scheme-specific dereferencing process (if any) + must be parsed and separated before the percent-encoded octets within + those components can be safely decoded, as otherwise the data may be + mistaken for component delimiters. The only exception is for + percent-encoded octets corresponding to characters in the unreserved + set, which can be decoded at any time. For example, the octet + corresponding to the tilde ("~") character is often encoded as "%7E" + by older URI processing implementations; the "%7E" can be replaced by + "~" without changing its interpretation. + + Because the percent ("%") character serves as the indicator for + percent-encoded octets, it must be percent-encoded as "%25" for that + octet to be used as data within a URI. Implementations must not + percent-encode or decode the same string more than once, as decoding + an already decoded string might lead to misinterpreting a percent + data octet as the beginning of a percent-encoding, or vice versa in + the case of percent-encoding an already percent-encoded string. + +2.5. Identifying Data + + URI characters provide identifying data for each of the URI + components, serving as an external interface for identification + between systems. Although the presence and nature of the URI + production interface is hidden from clients that use its URIs (and is + thus beyond the scope of the interoperability requirements defined by + this specification), it is a frequent source of confusion and errors + in the interpretation of URI character issues. Implementers have to + be aware that there are multiple character encodings involved in the + + + +Berners-Lee, et al. Standards Track [Page 14] + +RFC 3986 URI Generic Syntax January 2005 + + + production and transmission of URIs: local name and data encoding, + public interface encoding, URI character encoding, data format + encoding, and protocol encoding. + + Local names, such as file system names, are stored with a local + character encoding. URI producing applications (e.g., origin + servers) will typically use the local encoding as the basis for + producing meaningful names. The URI producer will transform the + local encoding to one that is suitable for a public interface and + then transform the public interface encoding into the restricted set + of URI characters (reserved, unreserved, and percent-encodings). + Those characters are, in turn, encoded as octets to be used as a + reference within a data format (e.g., a document charset), and such + data formats are often subsequently encoded for transmission over + Internet protocols. + + For most systems, an unreserved character appearing within a URI + component is interpreted as representing the data octet corresponding + to that character's encoding in US-ASCII. Consumers of URIs assume + that the letter "X" corresponds to the octet "01011000", and even + when that assumption is incorrect, there is no harm in making it. A + system that internally provides identifiers in the form of a + different character encoding, such as EBCDIC, will generally perform + character translation of textual identifiers to UTF-8 [STD63] (or + some other superset of the US-ASCII character encoding) at an + internal interface, thereby providing more meaningful identifiers + than those resulting from simply percent-encoding the original + octets. + + For example, consider an information service that provides data, + stored locally using an EBCDIC-based file system, to clients on the + Internet through an HTTP server. When an author creates a file with + the name "Laguna Beach" on that file system, the "http" URI + corresponding to that resource is expected to contain the meaningful + string "Laguna%20Beach". If, however, that server produces URIs by + using an overly simplistic raw octet mapping, then the result would + be a URI containing "%D3%81%87%A4%95%81@%C2%85%81%83%88". An + internal transcoding interface fixes this problem by transcoding the + local name to a superset of US-ASCII prior to producing the URI. + Naturally, proper interpretation of an incoming URI on such an + interface requires that percent-encoded octets be decoded (e.g., + "%20" to SP) before the reverse transcoding is applied to obtain the + local name. + + In some cases, the internal interface between a URI component and the + identifying data that it has been crafted to represent is much less + direct than a character encoding translation. For example, portions + of a URI might reflect a query on non-ASCII data, or numeric + + + +Berners-Lee, et al. Standards Track [Page 15] + +RFC 3986 URI Generic Syntax January 2005 + + + coordinates on a map. Likewise, a URI scheme may define components + with additional encoding requirements that are applied prior to + forming the component and producing the URI. + + When a new URI scheme defines a component that represents textual + data consisting of characters from the Universal Character Set [UCS], + the data should first be encoded as octets according to the UTF-8 + character encoding [STD63]; then only those octets that do not + correspond to characters in the unreserved set should be percent- + encoded. For example, the character A would be represented as "A", + the character LATIN CAPITAL LETTER A WITH GRAVE would be represented + as "%C3%80", and the character KATAKANA LETTER A would be represented + as "%E3%82%A2". + +3. Syntax Components + + The generic URI syntax consists of a hierarchical sequence of + components referred to as the scheme, authority, path, query, and + fragment. + + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + The scheme and path components are required, though the path may be + empty (no characters). When authority is present, the path must + either be empty or begin with a slash ("/") character. When + authority is not present, the path cannot begin with two slash + characters ("//"). These restrictions result in five different ABNF + rules for a path (Section 3.3), only one of which will match any + given URI reference. + + The following are two example URIs and their component parts: + + foo://example.com:8042/over/there?name=ferret#nose + \_/ \______________/\_________/ \_________/ \__/ + | | | | | + scheme authority path query fragment + | _____________________|__ + / \ / \ + urn:example:animal:ferret:nose + + + + + + + +Berners-Lee, et al. Standards Track [Page 16] + +RFC 3986 URI Generic Syntax January 2005 + + +3.1. Scheme + + Each URI begins with a scheme name that refers to a specification for + assigning identifiers within that scheme. As such, the URI syntax is + a federated and extensible naming system wherein each scheme's + specification may further restrict the syntax and semantics of + identifiers using that scheme. + + Scheme names consist of a sequence of characters beginning with a + letter and followed by any combination of letters, digits, plus + ("+"), period ("."), or hyphen ("-"). Although schemes are case- + insensitive, the canonical form is lowercase and documents that + specify schemes must do so with lowercase letters. An implementation + should accept uppercase letters as equivalent to lowercase in scheme + names (e.g., allow "HTTP" as well as "http") for the sake of + robustness but should only produce lowercase scheme names for + consistency. + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + Individual schemes are not specified by this document. The process + for registration of new URI schemes is defined separately by [BCP35]. + The scheme registry maintains the mapping between scheme names and + their specifications. Advice for designers of new URI schemes can be + found in [RFC2718]. URI scheme specifications must define their own + syntax so that all strings matching their scheme-specific syntax will + also match the <absolute-URI> grammar, as described in Section 4.3. + + When presented with a URI that violates one or more scheme-specific + restrictions, the scheme-specific resolution process should flag the + reference as an error rather than ignore the unused parts; doing so + reduces the number of equivalent URIs and helps detect abuses of the + generic syntax, which might indicate that the URI has been + constructed to mislead the user (Section 7.6). + +3.2. Authority + + Many URI schemes include a hierarchical element for a naming + authority so that governance of the name space defined by the + remainder of the URI is delegated to that authority (which may, in + turn, delegate it further). The generic syntax provides a common + means for distinguishing an authority based on a registered name or + server address, along with optional port and user information. + + The authority component is preceded by a double slash ("//") and is + terminated by the next slash ("/"), question mark ("?"), or number + sign ("#") character, or by the end of the URI. + + + + +Berners-Lee, et al. Standards Track [Page 17] + +RFC 3986 URI Generic Syntax January 2005 + + + authority = [ userinfo "@" ] host [ ":" port ] + + URI producers and normalizers should omit the ":" delimiter that + separates host from port if the port component is empty. Some + schemes do not allow the userinfo and/or port subcomponents. + + If a URI contains an authority component, then the path component + must either be empty or begin with a slash ("/") character. Non- + validating parsers (those that merely separate a URI reference into + its major components) will often ignore the subcomponent structure of + authority, treating it as an opaque string from the double-slash to + the first terminating delimiter, until such time as the URI is + dereferenced. + +3.2.1. User Information + + The userinfo subcomponent may consist of a user name and, optionally, + scheme-specific information about how to gain authorization to access + the resource. The user information, if present, is followed by a + commercial at-sign ("@") that delimits it from the host. + + userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + + Use of the format "user:password" in the userinfo field is + deprecated. Applications should not render as clear text any data + after the first colon (":") character found within a userinfo + subcomponent unless the data after the colon is the empty string + (indicating no password). Applications may choose to ignore or + reject such data when it is received as part of a reference and + should reject the storage of such data in unencrypted form. The + passing of authentication information in clear text has proven to be + a security risk in almost every case where it has been used. + + Applications that render a URI for the sake of user feedback, such as + in graphical hypertext browsing, should render userinfo in a way that + is distinguished from the rest of a URI, when feasible. Such + rendering will assist the user in cases where the userinfo has been + misleadingly crafted to look like a trusted domain name + (Section 7.6). + +3.2.2. Host + + The host subcomponent of authority is identified by an IP literal + encapsulated within square brackets, an IPv4 address in dotted- + decimal form, or a registered name. The host subcomponent is case- + insensitive. The presence of a host subcomponent within a URI does + not imply that the scheme requires access to the given host on the + Internet. In many cases, the host syntax is used only for the sake + + + +Berners-Lee, et al. Standards Track [Page 18] + +RFC 3986 URI Generic Syntax January 2005 + + + of reusing the existing registration process created and deployed for + DNS, thus obtaining a globally unique name without the cost of + deploying another registry. However, such use comes with its own + costs: domain name ownership may change over time for reasons not + anticipated by the URI producer. In other cases, the data within the + host component identifies a registered name that has nothing to do + with an Internet host. We use the name "host" for the ABNF rule + because that is its most common purpose, not its only purpose. + + host = IP-literal / IPv4address / reg-name + + The syntax rule for host is ambiguous because it does not completely + distinguish between an IPv4address and a reg-name. In order to + disambiguate the syntax, we apply the "first-match-wins" algorithm: + If host matches the rule for IPv4address, then it should be + considered an IPv4 address literal and not a reg-name. Although host + is case-insensitive, producers and normalizers should use lowercase + for registered names and hexadecimal addresses for the sake of + uniformity, while only using uppercase letters for percent-encodings. + + A host identified by an Internet Protocol literal address, version 6 + [RFC3513] or later, is distinguished by enclosing the IP literal + within square brackets ("[" and "]"). This is the only place where + square bracket characters are allowed in the URI syntax. In + anticipation of future, as-yet-undefined IP literal address formats, + an implementation may use an optional version flag to indicate such a + format explicitly rather than rely on heuristic determination. + + IP-literal = "[" ( IPv6address / IPvFuture ) "]" + + IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + + The version flag does not indicate the IP version; rather, it + indicates future versions of the literal format. As such, + implementations must not provide the version flag for the existing + IPv4 and IPv6 literal address forms described below. If a URI + containing an IP-literal that starts with "v" (case-insensitive), + indicating that the version flag is present, is dereferenced by an + application that does not know the meaning of that version flag, then + the application should return an appropriate error for "address + mechanism not supported". + + A host identified by an IPv6 literal address is represented inside + the square brackets without a preceding version flag. The ABNF + provided here is a translation of the text definition of an IPv6 + literal address provided in [RFC3513]. This syntax does not support + IPv6 scoped addressing zone identifiers. + + + + +Berners-Lee, et al. Standards Track [Page 19] + +RFC 3986 URI Generic Syntax January 2005 + + + A 128-bit IPv6 address is divided into eight 16-bit pieces. Each + piece is represented numerically in case-insensitive hexadecimal, + using one to four hexadecimal digits (leading zeroes are permitted). + The eight encoded pieces are given most-significant first, separated + by colon characters. Optionally, the least-significant two pieces + may instead be represented in IPv4 address textual format. A + sequence of one or more consecutive zero-valued 16-bit pieces within + the address may be elided, omitting all their digits and leaving + exactly two consecutive colons in their place to mark the elision. + + IPv6address = 6( h16 ":" ) ls32 + / "::" 5( h16 ":" ) ls32 + / [ h16 ] "::" 4( h16 ":" ) ls32 + / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + / [ *4( h16 ":" ) h16 ] "::" ls32 + / [ *5( h16 ":" ) h16 ] "::" h16 + / [ *6( h16 ":" ) h16 ] "::" + + ls32 = ( h16 ":" h16 ) / IPv4address + ; least-significant 32 bits of address + + h16 = 1*4HEXDIG + ; 16 bits of address represented in hexadecimal + + A host identified by an IPv4 literal address is represented in + dotted-decimal notation (a sequence of four decimal numbers in the + range 0 to 255, separated by "."), as described in [RFC1123] by + reference to [RFC0952]. Note that other forms of dotted notation may + be interpreted on some platforms, as described in Section 7.4, but + only the dotted-decimal form of four octets is allowed by this + grammar. + + IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + + dec-octet = DIGIT ; 0-9 + / %x31-39 DIGIT ; 10-99 + / "1" 2DIGIT ; 100-199 + / "2" %x30-34 DIGIT ; 200-249 + / "25" %x30-35 ; 250-255 + + A host identified by a registered name is a sequence of characters + usually intended for lookup within a locally defined host or service + name registry, though the URI's scheme-specific semantics may require + that a specific registry (or fixed name table) be used instead. The + most common name registry mechanism is the Domain Name System (DNS). + A registered name intended for lookup in the DNS uses the syntax + + + +Berners-Lee, et al. Standards Track [Page 20] + +RFC 3986 URI Generic Syntax January 2005 + + + defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123]. + Such a name consists of a sequence of domain labels separated by ".", + each domain label starting and ending with an alphanumeric character + and possibly also containing "-" characters. The rightmost domain + label of a fully qualified domain name in DNS may be followed by a + single "." and should be if it is necessary to distinguish between + the complete domain name and some local domain. + + reg-name = *( unreserved / pct-encoded / sub-delims ) + + If the URI scheme defines a default for host, then that default + applies when the host subcomponent is undefined or when the + registered name is empty (zero length). For example, the "file" URI + scheme is defined so that no authority, an empty host, and + "localhost" all mean the end-user's machine, whereas the "http" + scheme considers a missing authority or empty host invalid. + + This specification does not mandate a particular registered name + lookup technology and therefore does not restrict the syntax of reg- + name beyond what is necessary for interoperability. Instead, it + delegates the issue of registered name syntax conformance to the + operating system of each application performing URI resolution, and + that operating system decides what it will allow for the purpose of + host identification. A URI resolution implementation might use DNS, + host tables, yellow pages, NetInfo, WINS, or any other system for + lookup of registered names. However, a globally scoped naming + system, such as DNS fully qualified domain names, is necessary for + URIs intended to have global scope. URI producers should use names + that conform to the DNS syntax, even when use of DNS is not + immediately apparent, and should limit these names to no more than + 255 characters in length. + + The reg-name syntax allows percent-encoded octets in order to + represent non-ASCII registered names in a uniform way that is + independent of the underlying name resolution technology. Non-ASCII + characters must first be encoded according to UTF-8 [STD63], and then + each octet of the corresponding UTF-8 sequence must be percent- + encoded to be represented as URI characters. URI producing + applications must not use percent-encoding in host unless it is used + to represent a UTF-8 character sequence. When a non-ASCII registered + name represents an internationalized domain name intended for + resolution via the DNS, the name must be transformed to the IDNA + encoding [RFC3490] prior to name lookup. URI producers should + provide these registered names in the IDNA encoding, rather than a + percent-encoding, if they wish to maximize interoperability with + legacy URI resolvers. + + + + + +Berners-Lee, et al. Standards Track [Page 21] + +RFC 3986 URI Generic Syntax January 2005 + + +3.2.3. Port + + The port subcomponent of authority is designated by an optional port + number in decimal following the host and delimited from it by a + single colon (":") character. + + port = *DIGIT + + A scheme may define a default port. For example, the "http" scheme + defines a default port of "80", corresponding to its reserved TCP + port number. The type of port designated by the port number (e.g., + TCP, UDP, SCTP) is defined by the URI scheme. URI producers and + normalizers should omit the port component and its ":" delimiter if + port is empty or if its value would be the same as that of the + scheme's default. + +3.3. Path + + The path component contains data, usually organized in hierarchical + form, that, along with data in the non-hierarchical query component + (Section 3.4), serves to identify a resource within the scope of the + URI's scheme and naming authority (if any). The path is terminated + by the first question mark ("?") or number sign ("#") character, or + by the end of the URI. + + If a URI contains an authority component, then the path component + must either be empty or begin with a slash ("/") character. If a URI + does not contain an authority component, then the path cannot begin + with two slash characters ("//"). In addition, a URI reference + (Section 4.1) may be a relative-path reference, in which case the + first path segment cannot contain a colon (":") character. The ABNF + requires five separate rules to disambiguate these cases, only one of + which will match the path substring within a given URI reference. We + use the generic term "path component" to describe the URI substring + matched by the parser to one of these rules. + + path = path-abempty ; begins with "/" or is empty + / path-absolute ; begins with "/" but not "//" + / path-noscheme ; begins with a non-colon segment + / path-rootless ; begins with a segment + / path-empty ; zero characters + + path-abempty = *( "/" segment ) + path-absolute = "/" [ segment-nz *( "/" segment ) ] + path-noscheme = segment-nz-nc *( "/" segment ) + path-rootless = segment-nz *( "/" segment ) + path-empty = 0<pchar> + + + + +Berners-Lee, et al. Standards Track [Page 22] + +RFC 3986 URI Generic Syntax January 2005 + + + segment = *pchar + segment-nz = 1*pchar + segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + ; non-zero-length segment without any colon ":" + + pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + + A path consists of a sequence of path segments separated by a slash + ("/") character. A path is always defined for a URI, though the + defined path may be empty (zero length). Use of the slash character + to indicate hierarchy is only required when a URI will be used as the + context for relative references. For example, the URI + <mailto:[email protected]> has a path of "[email protected]", whereas + the URI <foo://info.example.com?fred> has an empty path. + + The path segments "." and "..", also known as dot-segments, are + defined for relative reference within the path name hierarchy. They + are intended for use at the beginning of a relative-path reference + (Section 4.2) to indicate relative position within the hierarchical + tree of names. This is similar to their role within some operating + systems' file directory structures to indicate the current directory + and parent directory, respectively. However, unlike in a file + system, these dot-segments are only interpreted within the URI path + hierarchy and are removed as part of the resolution process (Section + 5.2). + + Aside from dot-segments in hierarchical paths, a path segment is + considered opaque by the generic syntax. URI producing applications + often use the reserved characters allowed in a segment to delimit + scheme-specific or dereference-handler-specific subcomponents. For + example, the semicolon (";") and equals ("=") reserved characters are + often used to delimit parameters and parameter values applicable to + that segment. The comma (",") reserved character is often used for + similar purposes. For example, one URI producer might use a segment + such as "name;v=1.1" to indicate a reference to version 1.1 of + "name", whereas another might use a segment such as "name,1.1" to + indicate the same. Parameter types may be defined by scheme-specific + semantics, but in most cases the syntax of a parameter is specific to + the implementation of the URI's dereferencing algorithm. + +3.4. Query + + The query component contains non-hierarchical data that, along with + data in the path component (Section 3.3), serves to identify a + resource within the scope of the URI's scheme and naming authority + (if any). The query component is indicated by the first question + mark ("?") character and terminated by a number sign ("#") character + or by the end of the URI. + + + +Berners-Lee, et al. Standards Track [Page 23] + +RFC 3986 URI Generic Syntax January 2005 + + + query = *( pchar / "/" / "?" ) + + The characters slash ("/") and question mark ("?") may represent data + within the query component. Beware that some older, erroneous + implementations may not handle such data correctly when it is used as + the base URI for relative references (Section 5.1), apparently + because they fail to distinguish query data from path data when + looking for hierarchical separators. However, as query components + are often used to carry identifying information in the form of + "key=value" pairs and one frequently used value is a reference to + another URI, it is sometimes better for usability to avoid percent- + encoding those characters. + +3.5. Fragment + + The fragment identifier component of a URI allows indirect + identification of a secondary resource by reference to a primary + resource and additional identifying information. The identified + secondary resource may be some portion or subset of the primary + resource, some view on representations of the primary resource, or + some other resource defined or described by those representations. A + fragment identifier component is indicated by the presence of a + number sign ("#") character and terminated by the end of the URI. + + fragment = *( pchar / "/" / "?" ) + + The semantics of a fragment identifier are defined by the set of + representations that might result from a retrieval action on the + primary resource. The fragment's format and resolution is therefore + dependent on the media type [RFC2046] of a potentially retrieved + representation, even though such a retrieval is only performed if the + URI is dereferenced. If no such representation exists, then the + semantics of the fragment are considered unknown and are effectively + unconstrained. Fragment identifier semantics are independent of the + URI scheme and thus cannot be redefined by scheme specifications. + + Individual media types may define their own restrictions on or + structures within the fragment identifier syntax for specifying + different types of subsets, views, or external references that are + identifiable as secondary resources by that media type. If the + primary resource has multiple representations, as is often the case + for resources whose representation is selected based on attributes of + the retrieval request (a.k.a., content negotiation), then whatever is + identified by the fragment should be consistent across all of those + representations. Each representation should either define the + fragment so that it corresponds to the same secondary resource, + regardless of how it is represented, or should leave the fragment + undefined (i.e., not found). + + + +Berners-Lee, et al. Standards Track [Page 24] + +RFC 3986 URI Generic Syntax January 2005 + + + As with any URI, use of a fragment identifier component does not + imply that a retrieval action will take place. A URI with a fragment + identifier may be used to refer to the secondary resource without any + implication that the primary resource is accessible or will ever be + accessed. + + Fragment identifiers have a special role in information retrieval + systems as the primary form of client-side indirect referencing, + allowing an author to specifically identify aspects of an existing + resource that are only indirectly provided by the resource owner. As + such, the fragment identifier is not used in the scheme-specific + processing of a URI; instead, the fragment identifier is separated + from the rest of the URI prior to a dereference, and thus the + identifying information within the fragment itself is dereferenced + solely by the user agent, regardless of the URI scheme. Although + this separate handling is often perceived to be a loss of + information, particularly for accurate redirection of references as + resources move over time, it also serves to prevent information + providers from denying reference authors the right to refer to + information within a resource selectively. Indirect referencing also + provides additional flexibility and extensibility to systems that use + URIs, as new media types are easier to define and deploy than new + schemes of identification. + + The characters slash ("/") and question mark ("?") are allowed to + represent data within the fragment identifier. Beware that some + older, erroneous implementations may not handle this data correctly + when it is used as the base URI for relative references (Section + 5.1). + +4. Usage + + When applications make reference to a URI, they do not always use the + full form of reference defined by the "URI" syntax rule. To save + space and take advantage of hierarchical locality, many Internet + protocol elements and media type formats allow an abbreviation of a + URI, whereas others restrict the syntax to a particular form of URI. + We define the most common forms of reference syntax in this + specification because they impact and depend upon the design of the + generic syntax, requiring a uniform parsing algorithm in order to be + interpreted consistently. + +4.1. URI Reference + + URI-reference is used to denote the most common usage of a resource + identifier. + + URI-reference = URI / relative-ref + + + +Berners-Lee, et al. Standards Track [Page 25] + +RFC 3986 URI Generic Syntax January 2005 + + + A URI-reference is either a URI or a relative reference. If the + URI-reference's prefix does not match the syntax of a scheme followed + by its colon separator, then the URI-reference is a relative + reference. + + A URI-reference is typically parsed first into the five URI + components, in order to determine what components are present and + whether the reference is relative. Then, each component is parsed + for its subparts and their validation. The ABNF of URI-reference, + along with the "first-match-wins" disambiguation rule, is sufficient + to define a validating parser for the generic syntax. Readers + familiar with regular expressions should see Appendix B for an + example of a non-validating URI-reference parser that will take any + given string and extract the URI components. + +4.2. Relative Reference + + A relative reference takes advantage of the hierarchical syntax + (Section 1.2.3) to express a URI reference relative to the name space + of another hierarchical URI. + + relative-ref = relative-part [ "?" query ] [ "#" fragment ] + + relative-part = "//" authority path-abempty + / path-absolute + / path-noscheme + / path-empty + + The URI referred to by a relative reference, also known as the target + URI, is obtained by applying the reference resolution algorithm of + Section 5. + + A relative reference that begins with two slash characters is termed + a network-path reference; such references are rarely used. A + relative reference that begins with a single slash character is + termed an absolute-path reference. A relative reference that does + not begin with a slash character is termed a relative-path reference. + + A path segment that contains a colon character (e.g., "this:that") + cannot be used as the first segment of a relative-path reference, as + it would be mistaken for a scheme name. Such a segment must be + preceded by a dot-segment (e.g., "./this:that") to make a relative- + path reference. + + + + + + + + +Berners-Lee, et al. Standards Track [Page 26] + +RFC 3986 URI Generic Syntax January 2005 + + +4.3. Absolute URI + + Some protocol elements allow only the absolute form of a URI without + a fragment identifier. For example, defining a base URI for later + use by relative references calls for an absolute-URI syntax rule that + does not allow a fragment. + + absolute-URI = scheme ":" hier-part [ "?" query ] + + URI scheme specifications must define their own syntax so that all + strings matching their scheme-specific syntax will also match the + <absolute-URI> grammar. Scheme specifications will not define + fragment identifier syntax or usage, regardless of its applicability + to resources identifiable via that scheme, as fragment identification + is orthogonal to scheme definition. However, scheme specifications + are encouraged to include a wide range of examples, including + examples that show use of the scheme's URIs with fragment identifiers + when such usage is appropriate. + +4.4. Same-Document Reference + + When a URI reference refers to a URI that is, aside from its fragment + component (if any), identical to the base URI (Section 5.1), that + reference is called a "same-document" reference. The most frequent + examples of same-document references are relative references that are + empty or include only the number sign ("#") separator followed by a + fragment identifier. + + When a same-document reference is dereferenced for a retrieval + action, the target of that reference is defined to be within the same + entity (representation, document, or message) as the reference; + therefore, a dereference should not result in a new retrieval action. + + Normalization of the base and target URIs prior to their comparison, + as described in Sections 6.2.2 and 6.2.3, is allowed but rarely + performed in practice. Normalization may increase the set of same- + document references, which may be of benefit to some caching + applications. As such, reference authors should not assume that a + slightly different, though equivalent, reference URI will (or will + not) be interpreted as a same-document reference by any given + application. + +4.5. Suffix Reference + + The URI syntax is designed for unambiguous reference to resources and + extensibility via the URI scheme. However, as URI identification and + usage have become commonplace, traditional media (television, radio, + newspapers, billboards, etc.) have increasingly used a suffix of the + + + +Berners-Lee, et al. Standards Track [Page 27] + +RFC 3986 URI Generic Syntax January 2005 + + + URI as a reference, consisting of only the authority and path + portions of the URI, such as + + www.w3.org/Addressing/ + + or simply a DNS registered name on its own. Such references are + primarily intended for human interpretation rather than for machines, + with the assumption that context-based heuristics are sufficient to + complete the URI (e.g., most registered names beginning with "www" + are likely to have a URI prefix of "http://"). Although there is no + standard set of heuristics for disambiguating a URI suffix, many + client implementations allow them to be entered by the user and + heuristically resolved. + + Although this practice of using suffix references is common, it + should be avoided whenever possible and should never be used in + situations where long-term references are expected. The heuristics + noted above will change over time, particularly when a new URI scheme + becomes popular, and are often incorrect when used out of context. + Furthermore, they can lead to security issues along the lines of + those described in [RFC1535]. + + As a URI suffix has the same syntax as a relative-path reference, a + suffix reference cannot be used in contexts where a relative + reference is expected. As a result, suffix references are limited to + places where there is no defined base URI, such as dialog boxes and + off-line advertisements. + +5. Reference Resolution + + This section defines the process of resolving a URI reference within + a context that allows relative references so that the result is a + string matching the <URI> syntax rule of Section 3. + +5.1. Establishing a Base URI + + The term "relative" implies that a "base URI" exists against which + the relative reference is applied. Aside from fragment-only + references (Section 4.4), relative references are only usable when a + base URI is known. A base URI must be established by the parser + prior to parsing URI references that might be relative. A base URI + must conform to the <absolute-URI> syntax rule (Section 4.3). If the + base URI is obtained from a URI reference, then that reference must + be converted to absolute form and stripped of any fragment component + prior to its use as a base URI. + + + + + + +Berners-Lee, et al. Standards Track [Page 28] + +RFC 3986 URI Generic Syntax January 2005 + + + The base URI of a reference can be established in one of four ways, + discussed below in order of precedence. The order of precedence can + be thought of in terms of layers, where the innermost defined base + URI has the highest precedence. This can be visualized graphically + as follows: + + .----------------------------------------------------------. + | .----------------------------------------------------. | + | | .----------------------------------------------. | | + | | | .----------------------------------------. | | | + | | | | .----------------------------------. | | | | + | | | | | <relative-reference> | | | | | + | | | | `----------------------------------' | | | | + | | | | (5.1.1) Base URI embedded in content | | | | + | | | `----------------------------------------' | | | + | | | (5.1.2) Base URI of the encapsulating entity | | | + | | | (message, representation, or none) | | | + | | `----------------------------------------------' | | + | | (5.1.3) URI used to retrieve the entity | | + | `----------------------------------------------------' | + | (5.1.4) Default Base URI (application-dependent) | + `----------------------------------------------------------' + +5.1.1. Base URI Embedded in Content + + Within certain media types, a base URI for relative references can be + embedded within the content itself so that it can be readily obtained + by a parser. This can be useful for descriptive documents, such as + tables of contents, which may be transmitted to others through + protocols other than their usual retrieval context (e.g., email or + USENET news). + + It is beyond the scope of this specification to specify how, for each + media type, a base URI can be embedded. The appropriate syntax, when + available, is described by the data format specification associated + with each media type. + +5.1.2. Base URI from the Encapsulating Entity + + If no base URI is embedded, the base URI is defined by the + representation's retrieval context. For a document that is enclosed + within another entity, such as a message or archive, the retrieval + context is that entity. Thus, the default base URI of a + representation is the base URI of the entity in which the + representation is encapsulated. + + + + + + +Berners-Lee, et al. Standards Track [Page 29] + +RFC 3986 URI Generic Syntax January 2005 + + + A mechanism for embedding a base URI within MIME container types + (e.g., the message and multipart types) is defined by MHTML + [RFC2557]. Protocols that do not use the MIME message header syntax, + but that do allow some form of tagged metadata to be included within + messages, may define their own syntax for defining a base URI as part + of a message. + +5.1.3. Base URI from the Retrieval URI + + If no base URI is embedded and the representation is not encapsulated + within some other entity, then, if a URI was used to retrieve the + representation, that URI shall be considered the base URI. Note that + if the retrieval was the result of a redirected request, the last URI + used (i.e., the URI that resulted in the actual retrieval of the + representation) is the base URI. + +5.1.4. Default Base URI + + If none of the conditions described above apply, then the base URI is + defined by the context of the application. As this definition is + necessarily application-dependent, failing to define a base URI by + using one of the other methods may result in the same content being + interpreted differently by different types of applications. + + A sender of a representation containing relative references is + responsible for ensuring that a base URI for those references can be + established. Aside from fragment-only references, relative + references can only be used reliably in situations where the base URI + is well defined. + +5.2. Relative Resolution + + This section describes an algorithm for converting a URI reference + that might be relative to a given base URI into the parsed components + of the reference's target. The components can then be recomposed, as + described in Section 5.3, to form the target URI. This algorithm + provides definitive results that can be used to test the output of + other implementations. Applications may implement relative reference + resolution by using some other algorithm, provided that the results + match what would be given by this one. + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 30] + +RFC 3986 URI Generic Syntax January 2005 + + +5.2.1. Pre-parse the Base URI + + The base URI (Base) is established according to the procedure of + Section 5.1 and parsed into the five main components described in + Section 3. Note that only the scheme component is required to be + present in a base URI; the other components may be empty or + undefined. A component is undefined if its associated delimiter does + not appear in the URI reference; the path component is never + undefined, though it may be empty. + + Normalization of the base URI, as described in Sections 6.2.2 and + 6.2.3, is optional. A URI reference must be transformed to its + target URI before it can be normalized. + +5.2.2. Transform References + + For each URI reference (R), the following pseudocode describes an + algorithm for transforming R into its target URI (T): + + -- The URI reference is parsed into the five URI components + -- + (R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R); + + -- A non-strict parser may ignore a scheme in the reference + -- if it is identical to the base URI's scheme. + -- + if ((not strict) and (R.scheme == Base.scheme)) then + undefine(R.scheme); + endif; + + + + + + + + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 31] + +RFC 3986 URI Generic Syntax January 2005 + + + if defined(R.scheme) then + T.scheme = R.scheme; + T.authority = R.authority; + T.path = remove_dot_segments(R.path); + T.query = R.query; + else + if defined(R.authority) then + T.authority = R.authority; + T.path = remove_dot_segments(R.path); + T.query = R.query; + else + if (R.path == "") then + T.path = Base.path; + if defined(R.query) then + T.query = R.query; + else + T.query = Base.query; + endif; + else + if (R.path starts-with "/") then + T.path = remove_dot_segments(R.path); + else + T.path = merge(Base.path, R.path); + T.path = remove_dot_segments(T.path); + endif; + T.query = R.query; + endif; + T.authority = Base.authority; + endif; + T.scheme = Base.scheme; + endif; + + T.fragment = R.fragment; + +5.2.3. Merge Paths + + The pseudocode above refers to a "merge" routine for merging a + relative-path reference with the path of the base URI. This is + accomplished as follows: + + o If the base URI has a defined authority component and an empty + path, then return a string consisting of "/" concatenated with the + reference's path; otherwise, + + + + + + + + +Berners-Lee, et al. Standards Track [Page 32] + +RFC 3986 URI Generic Syntax January 2005 + + + o return a string consisting of the reference's path component + appended to all but the last segment of the base URI's path (i.e., + excluding any characters after the right-most "/" in the base URI + path, or excluding the entire base URI path if it does not contain + any "/" characters). + +5.2.4. Remove Dot Segments + + The pseudocode also refers to a "remove_dot_segments" routine for + interpreting and removing the special "." and ".." complete path + segments from a referenced path. This is done after the path is + extracted from a reference, whether or not the path was relative, in + order to remove any invalid or extraneous dot-segments prior to + forming the target URI. Although there are many ways to accomplish + this removal process, we describe a simple method using two string + buffers. + + 1. The input buffer is initialized with the now-appended path + components and the output buffer is initialized to the empty + string. + + 2. While the input buffer is not empty, loop as follows: + + A. If the input buffer begins with a prefix of "../" or "./", + then remove that prefix from the input buffer; otherwise, + + B. if the input buffer begins with a prefix of "/./" or "/.", + where "." is a complete path segment, then replace that + prefix with "/" in the input buffer; otherwise, + + C. if the input buffer begins with a prefix of "/../" or "/..", + where ".." is a complete path segment, then replace that + prefix with "/" in the input buffer and remove the last + segment and its preceding "/" (if any) from the output + buffer; otherwise, + + D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, + + E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if + any) and any subsequent characters up to, but not including, + the next "/" character or the end of the input buffer. + + 3. Finally, the output buffer is returned as the result of + remove_dot_segments. + + + + + +Berners-Lee, et al. Standards Track [Page 33] + +RFC 3986 URI Generic Syntax January 2005 + + + Note that dot-segments are intended for use in URI references to + express an identifier relative to the hierarchy of names in the base + URI. The remove_dot_segments algorithm respects that hierarchy by + removing extra dot-segments rather than treat them as an error or + leaving them to be misinterpreted by dereference implementations. + + The following illustrates how the above steps are applied for two + examples of merged paths, showing the state of the two buffers after + each step. + + STEP OUTPUT BUFFER INPUT BUFFER + + 1 : /a/b/c/./../../g + 2E: /a /b/c/./../../g + 2E: /a/b /c/./../../g + 2E: /a/b/c /./../../g + 2B: /a/b/c /../../g + 2C: /a/b /../g + 2C: /a /g + 2E: /a/g + + STEP OUTPUT BUFFER INPUT BUFFER + + 1 : mid/content=5/../6 + 2E: mid /content=5/../6 + 2E: mid/content=5 /../6 + 2C: mid /6 + 2E: mid/6 + + Some applications may find it more efficient to implement the + remove_dot_segments algorithm by using two segment stacks rather than + strings. + + Note: Beware that some older, erroneous implementations will fail + to separate a reference's query component from its path component + prior to merging the base and reference paths, resulting in an + interoperability failure if the query component contains the + strings "/../" or "/./". + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 34] + +RFC 3986 URI Generic Syntax January 2005 + + +5.3. Component Recomposition + + Parsed URI components can be recomposed to obtain the corresponding + URI reference string. Using pseudocode, this would be: + + result = "" + + if defined(scheme) then + append scheme to result; + append ":" to result; + endif; + + if defined(authority) then + append "//" to result; + append authority to result; + endif; + + append path to result; + + if defined(query) then + append "?" to result; + append query to result; + endif; + + if defined(fragment) then + append "#" to result; + append fragment to result; + endif; + + return result; + + Note that we are careful to preserve the distinction between a + component that is undefined, meaning that its separator was not + present in the reference, and a component that is empty, meaning that + the separator was present and was immediately followed by the next + component separator or the end of the reference. + +5.4. Reference Resolution Examples + + Within a representation with a well defined base URI of + + http://a/b/c/d;p?q + + a relative reference is transformed to its target URI as follows. + + + + + + + +Berners-Lee, et al. Standards Track [Page 35] + +RFC 3986 URI Generic Syntax January 2005 + + +5.4.1. Normal Examples + + "g:h" = "g:h" + "g" = "http://a/b/c/g" + "./g" = "http://a/b/c/g" + "g/" = "http://a/b/c/g/" + "/g" = "http://a/g" + "//g" = "http://g" + "?y" = "http://a/b/c/d;p?y" + "g?y" = "http://a/b/c/g?y" + "#s" = "http://a/b/c/d;p?q#s" + "g#s" = "http://a/b/c/g#s" + "g?y#s" = "http://a/b/c/g?y#s" + ";x" = "http://a/b/c/;x" + "g;x" = "http://a/b/c/g;x" + "g;x?y#s" = "http://a/b/c/g;x?y#s" + "" = "http://a/b/c/d;p?q" + "." = "http://a/b/c/" + "./" = "http://a/b/c/" + ".." = "http://a/b/" + "../" = "http://a/b/" + "../g" = "http://a/b/g" + "../.." = "http://a/" + "../../" = "http://a/" + "../../g" = "http://a/g" + +5.4.2. Abnormal Examples + + Although the following abnormal examples are unlikely to occur in + normal practice, all URI parsers should be capable of resolving them + consistently. Each example uses the same base as that above. + + Parsers must be careful in handling cases where there are more ".." + segments in a relative-path reference than there are hierarchical + levels in the base URI's path. Note that the ".." syntax cannot be + used to change the authority component of a URI. + + "../../../g" = "http://a/g" + "../../../../g" = "http://a/g" + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 36] + +RFC 3986 URI Generic Syntax January 2005 + + + Similarly, parsers must remove the dot-segments "." and ".." when + they are complete components of a path, but not when they are only + part of a segment. + + "/./g" = "http://a/g" + "/../g" = "http://a/g" + "g." = "http://a/b/c/g." + ".g" = "http://a/b/c/.g" + "g.." = "http://a/b/c/g.." + "..g" = "http://a/b/c/..g" + + Less likely are cases where the relative reference uses unnecessary + or nonsensical forms of the "." and ".." complete path segments. + + "./../g" = "http://a/b/g" + "./g/." = "http://a/b/c/g/" + "g/./h" = "http://a/b/c/g/h" + "g/../h" = "http://a/b/c/h" + "g;x=1/./y" = "http://a/b/c/g;x=1/y" + "g;x=1/../y" = "http://a/b/c/y" + + Some applications fail to separate the reference's query and/or + fragment components from the path component before merging it with + the base path and removing dot-segments. This error is rarely + noticed, as typical usage of a fragment never includes the hierarchy + ("/") character and the query component is not normally used within + relative references. + + "g?y/./x" = "http://a/b/c/g?y/./x" + "g?y/../x" = "http://a/b/c/g?y/../x" + "g#s/./x" = "http://a/b/c/g#s/./x" + "g#s/../x" = "http://a/b/c/g#s/../x" + + Some parsers allow the scheme name to be present in a relative + reference if it is the same as the base URI scheme. This is + considered to be a loophole in prior specifications of partial URI + [RFC1630]. Its use should be avoided but is allowed for backward + compatibility. + + "http:g" = "http:g" ; for strict parsers + / "http://a/b/c/g" ; for backward compatibility + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 37] + +RFC 3986 URI Generic Syntax January 2005 + + +6. Normalization and Comparison + + One of the most common operations on URIs is simple comparison: + determining whether two URIs are equivalent without using the URIs to + access their respective resource(s). A comparison is performed every + time a response cache is accessed, a browser checks its history to + color a link, or an XML parser processes tags within a namespace. + Extensive normalization prior to comparison of URIs is often used by + spiders and indexing engines to prune a search space or to reduce + duplication of request actions and response storage. + + URI comparison is performed for some particular purpose. Protocols + or implementations that compare URIs for different purposes will + often be subject to differing design trade-offs in regards to how + much effort should be spent in reducing aliased identifiers. This + section describes various methods that may be used to compare URIs, + the trade-offs between them, and the types of applications that might + use them. + +6.1. Equivalence + + Because URIs exist to identify resources, presumably they should be + considered equivalent when they identify the same resource. However, + this definition of equivalence is not of much practical use, as there + is no way for an implementation to compare two resources unless it + has full knowledge or control of them. For this reason, + determination of equivalence or difference of URIs is based on string + comparison, perhaps augmented by reference to additional rules + provided by URI scheme definitions. We use the terms "different" and + "equivalent" to describe the possible outcomes of such comparisons, + but there are many application-dependent versions of equivalence. + + Even though it is possible to determine that two URIs are equivalent, + URI comparison is not sufficient to determine whether two URIs + identify different resources. For example, an owner of two different + domain names could decide to serve the same resource from both, + resulting in two different URIs. Therefore, comparison methods are + designed to minimize false negatives while strictly avoiding false + positives. + + In testing for equivalence, applications should not directly compare + relative references; the references should be converted to their + respective target URIs before comparison. When URIs are compared to + select (or avoid) a network action, such as retrieval of a + representation, fragment components (if any) should be excluded from + the comparison. + + + + + +Berners-Lee, et al. Standards Track [Page 38] + +RFC 3986 URI Generic Syntax January 2005 + + +6.2. Comparison Ladder + + A variety of methods are used in practice to test URI equivalence. + These methods fall into a range, distinguished by the amount of + processing required and the degree to which the probability of false + negatives is reduced. As noted above, false negatives cannot be + eliminated. In practice, their probability can be reduced, but this + reduction requires more processing and is not cost-effective for all + applications. + + If this range of comparison practices is considered as a ladder, the + following discussion will climb the ladder, starting with practices + that are cheap but have a relatively higher chance of producing false + negatives, and proceeding to those that have higher computational + cost and lower risk of false negatives. + +6.2.1. Simple String Comparison + + If two URIs, when considered as character strings, are identical, + then it is safe to conclude that they are equivalent. This type of + equivalence test has very low computational cost and is in wide use + in a variety of applications, particularly in the domain of parsing. + + Testing strings for equivalence requires some basic precautions. + This procedure is often referred to as "bit-for-bit" or + "byte-for-byte" comparison, which is potentially misleading. Testing + strings for equality is normally based on pair comparison of the + characters that make up the strings, starting from the first and + proceeding until both strings are exhausted and all characters are + found to be equal, until a pair of characters compares unequal, or + until one of the strings is exhausted before the other. + + This character comparison requires that each pair of characters be + put in comparable form. For example, should one URI be stored in a + byte array in EBCDIC encoding and the second in a Java String object + (UTF-16), bit-for-bit comparisons applied naively will produce + errors. It is better to speak of equality on a character-for- + character basis rather than on a byte-for-byte or bit-for-bit basis. + In practical terms, character-by-character comparisons should be done + codepoint-by-codepoint after conversion to a common character + encoding. + + False negatives are caused by the production and use of URI aliases. + Unnecessary aliases can be reduced, regardless of the comparison + method, by consistently providing URI references in an already- + normalized form (i.e., a form identical to what would be produced + after normalization is applied, as described below). + + + + +Berners-Lee, et al. Standards Track [Page 39] + +RFC 3986 URI Generic Syntax January 2005 + + + Protocols and data formats often limit some URI comparisons to simple + string comparison, based on the theory that people and + implementations will, in their own best interest, be consistent in + providing URI references, or at least consistent enough to negate any + efficiency that might be obtained from further normalization. + +6.2.2. Syntax-Based Normalization + + Implementations may use logic based on the definitions provided by + this specification to reduce the probability of false negatives. + This processing is moderately higher in cost than character-for- + character string comparison. For example, an application using this + approach could reasonably consider the following two URIs equivalent: + + example://a/b/c/%7Bfoo%7D + eXAMPLE://a/./b/../b/%63/%7bfoo%7d + + Web user agents, such as browsers, typically apply this type of URI + normalization when determining whether a cached response is + available. Syntax-based normalization includes such techniques as + case normalization, percent-encoding normalization, and removal of + dot-segments. + +6.2.2.1. Case Normalization + + For all URIs, the hexadecimal digits within a percent-encoding + triplet (e.g., "%3a" versus "%3A") are case-insensitive and therefore + should be normalized to use uppercase letters for the digits A-F. + + When a URI uses components of the generic syntax, the component + syntax equivalence rules always apply; namely, that the scheme and + host are case-insensitive and therefore should be normalized to + lowercase. For example, the URI <HTTP://www.EXAMPLE.com/> is + equivalent to <http://www.example.com/>. The other generic syntax + components are assumed to be case-sensitive unless specifically + defined otherwise by the scheme (see Section 6.2.3). + +6.2.2.2. Percent-Encoding Normalization + + The percent-encoding mechanism (Section 2.1) is a frequent source of + variance among otherwise identical URIs. In addition to the case + normalization issue noted above, some URI producers percent-encode + octets that do not require percent-encoding, resulting in URIs that + are equivalent to their non-encoded counterparts. These URIs should + be normalized by decoding any percent-encoded octet that corresponds + to an unreserved character, as described in Section 2.3. + + + + + +Berners-Lee, et al. Standards Track [Page 40] + +RFC 3986 URI Generic Syntax January 2005 + + +6.2.2.3. Path Segment Normalization + + The complete path segments "." and ".." are intended only for use + within relative references (Section 4.1) and are removed as part of + the reference resolution process (Section 5.2). However, some + deployed implementations incorrectly assume that reference resolution + is not necessary when the reference is already a URI and thus fail to + remove dot-segments when they occur in non-relative paths. URI + normalizers should remove dot-segments by applying the + remove_dot_segments algorithm to the path, as described in + Section 5.2.4. + +6.2.3. Scheme-Based Normalization + + The syntax and semantics of URIs vary from scheme to scheme, as + described by the defining specification for each scheme. + Implementations may use scheme-specific rules, at further processing + cost, to reduce the probability of false negatives. For example, + because the "http" scheme makes use of an authority component, has a + default port of "80", and defines an empty path to be equivalent to + "/", the following four URIs are equivalent: + + http://example.com + http://example.com/ + http://example.com:/ + http://example.com:80/ + + In general, a URI that uses the generic syntax for authority with an + empty path should be normalized to a path of "/". Likewise, an + explicit ":port", for which the port is empty or the default for the + scheme, is equivalent to one where the port and its ":" delimiter are + elided and thus should be removed by scheme-based normalization. For + example, the second URI above is the normal form for the "http" + scheme. + + Another case where normalization varies by scheme is in the handling + of an empty authority component or empty host subcomponent. For many + scheme specifications, an empty authority or host is considered an + error; for others, it is considered equivalent to "localhost" or the + end-user's host. When a scheme defines a default for authority and a + URI reference to that default is desired, the reference should be + normalized to an empty authority for the sake of uniformity, brevity, + and internationalization. If, however, either the userinfo or port + subcomponents are non-empty, then the host should be given explicitly + even if it matches the default. + + Normalization should not remove delimiters when their associated + component is empty unless licensed to do so by the scheme + + + +Berners-Lee, et al. Standards Track [Page 41] + +RFC 3986 URI Generic Syntax January 2005 + + + specification. For example, the URI "http://example.com/?" cannot be + assumed to be equivalent to any of the examples above. Likewise, the + presence or absence of delimiters within a userinfo subcomponent is + usually significant to its interpretation. The fragment component is + not subject to any scheme-based normalization; thus, two URIs that + differ only by the suffix "#" are considered different regardless of + the scheme. + + Some schemes define additional subcomponents that consist of case- + insensitive data, giving an implicit license to normalizers to + convert this data to a common case (e.g., all lowercase). For + example, URI schemes that define a subcomponent of path to contain an + Internet hostname, such as the "mailto" URI scheme, cause that + subcomponent to be case-insensitive and thus subject to case + normalization (e.g., "mailto:[email protected]" is equivalent to + "mailto:[email protected]", even though the generic syntax considers + the path component to be case-sensitive). + + Other scheme-specific normalizations are possible. + +6.2.4. Protocol-Based Normalization + + Substantial effort to reduce the incidence of false negatives is + often cost-effective for web spiders. Therefore, they implement even + more aggressive techniques in URI comparison. For example, if they + observe that a URI such as + + http://example.com/data + + redirects to a URI differing only in the trailing slash + + http://example.com/data/ + + they will likely regard the two as equivalent in the future. This + kind of technique is only appropriate when equivalence is clearly + indicated by both the result of accessing the resources and the + common conventions of their scheme's dereference algorithm (in this + case, use of redirection by HTTP origin servers to avoid problems + with relative references). + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 42] + +RFC 3986 URI Generic Syntax January 2005 + + +7. Security Considerations + + A URI does not in itself pose a security threat. However, as URIs + are often used to provide a compact set of instructions for access to + network resources, care must be taken to properly interpret the data + within a URI, to prevent that data from causing unintended access, + and to avoid including data that should not be revealed in plain + text. + +7.1. Reliability and Consistency + + There is no guarantee that once a URI has been used to retrieve + information, the same information will be retrievable by that URI in + the future. Nor is there any guarantee that the information + retrievable via that URI in the future will be observably similar to + that retrieved in the past. The URI syntax does not constrain how a + given scheme or authority apportions its namespace or maintains it + over time. Such guarantees can only be obtained from the person(s) + controlling that namespace and the resource in question. A specific + URI scheme may define additional semantics, such as name persistence, + if those semantics are required of all naming authorities for that + scheme. + +7.2. Malicious Construction + + It is sometimes possible to construct a URI so that an attempt to + perform a seemingly harmless, idempotent operation, such as the + retrieval of a representation, will in fact cause a possibly damaging + remote operation. The unsafe URI is typically constructed by + specifying a port number other than that reserved for the network + protocol in question. The client unwittingly contacts a site running + a different protocol service, and data within the URI contains + instructions that, when interpreted according to this other protocol, + cause an unexpected operation. A frequent example of such abuse has + been the use of a protocol-based scheme with a port component of + "25", thereby fooling user agent software into sending an unintended + or impersonating message via an SMTP server. + + Applications should prevent dereference of a URI that specifies a TCP + port number within the "well-known port" range (0 - 1023) unless the + protocol being used to dereference that URI is compatible with the + protocol expected on that well-known port. Although IANA maintains a + registry of well-known ports, applications should make such + restrictions user-configurable to avoid preventing the deployment of + new services. + + + + + + +Berners-Lee, et al. Standards Track [Page 43] + +RFC 3986 URI Generic Syntax January 2005 + + + When a URI contains percent-encoded octets that match the delimiters + for a given resolution or dereference protocol (for example, CR and + LF characters for the TELNET protocol), these percent-encodings must + not be decoded before transmission across that protocol. Transfer of + the percent-encoding, which might violate the protocol, is less + harmful than allowing decoded octets to be interpreted as additional + operations or parameters, perhaps triggering an unexpected and + possibly harmful remote operation. + +7.3. Back-End Transcoding + + When a URI is dereferenced, the data within it is often parsed by + both the user agent and one or more servers. In HTTP, for example, a + typical user agent will parse a URI into its five major components, + access the authority's server, and send it the data within the + authority, path, and query components. A typical server will take + that information, parse the path into segments and the query into + key/value pairs, and then invoke implementation-specific handlers to + respond to the request. As a result, a common security concern for + server implementations that handle a URI, either as a whole or split + into separate components, is proper interpretation of the octet data + represented by the characters and percent-encodings within that URI. + + Percent-encoded octets must be decoded at some point during the + dereference process. Applications must split the URI into its + components and subcomponents prior to decoding the octets, as + otherwise the decoded octets might be mistaken for delimiters. + Security checks of the data within a URI should be applied after + decoding the octets. Note, however, that the "%00" percent-encoding + (NUL) may require special handling and should be rejected if the + application is not expecting to receive raw data within a component. + + Special care should be taken when the URI path interpretation process + involves the use of a back-end file system or related system + functions. File systems typically assign an operational meaning to + special characters, such as the "/", "\", ":", "[", and "]" + characters, and to special device names like ".", "..", "...", "aux", + "lpt", etc. In some cases, merely testing for the existence of such + a name will cause the operating system to pause or invoke unrelated + system calls, leading to significant security concerns regarding + denial of service and unintended data transfer. It would be + impossible for this specification to list all such significant + characters and device names. Implementers should research the + reserved names and characters for the types of storage device that + may be attached to their applications and restrict the use of data + obtained from URI components accordingly. + + + + + +Berners-Lee, et al. Standards Track [Page 44] + +RFC 3986 URI Generic Syntax January 2005 + + +7.4. Rare IP Address Formats + + Although the URI syntax for IPv4address only allows the common + dotted-decimal form of IPv4 address literal, many implementations + that process URIs make use of platform-dependent system routines, + such as gethostbyname() and inet_aton(), to translate the string + literal to an actual IP address. Unfortunately, such system routines + often allow and process a much larger set of formats than those + described in Section 3.2.2. + + For example, many implementations allow dotted forms of three + numbers, wherein the last part is interpreted as a 16-bit quantity + and placed in the right-most two bytes of the network address (e.g., + a Class B network). Likewise, a dotted form of two numbers means + that the last part is interpreted as a 24-bit quantity and placed in + the right-most three bytes of the network address (Class A), and a + single number (without dots) is interpreted as a 32-bit quantity and + stored directly in the network address. Adding further to the + confusion, some implementations allow each dotted part to be + interpreted as decimal, octal, or hexadecimal, as specified in the C + language (i.e., a leading 0x or 0X implies hexadecimal; a leading 0 + implies octal; otherwise, the number is interpreted as decimal). + + These additional IP address formats are not allowed in the URI syntax + due to differences between platform implementations. However, they + can become a security concern if an application attempts to filter + access to resources based on the IP address in string literal format. + If this filtering is performed, literals should be converted to + numeric form and filtered based on the numeric value, and not on a + prefix or suffix of the string form. + +7.5. Sensitive Information + + URI producers should not provide a URI that contains a username or + password that is intended to be secret. URIs are frequently + displayed by browsers, stored in clear text bookmarks, and logged by + user agent history and intermediary applications (proxies). A + password appearing within the userinfo component is deprecated and + should be considered an error (or simply ignored) except in those + rare cases where the 'password' parameter is intended to be public. + +7.6. Semantic Attacks + + Because the userinfo subcomponent is rarely used and appears before + the host in the authority component, it can be used to construct a + URI intended to mislead a human user by appearing to identify one + (trusted) naming authority while actually identifying a different + authority hidden behind the noise. For example + + + +Berners-Lee, et al. Standards Track [Page 45] + +RFC 3986 URI Generic Syntax January 2005 + + + ftp://cnn.example.com&[email protected]/top_story.htm + + might lead a human user to assume that the host is 'cnn.example.com', + whereas it is actually '10.0.0.1'. Note that a misleading userinfo + subcomponent could be much longer than the example above. + + A misleading URI, such as that above, is an attack on the user's + preconceived notions about the meaning of a URI rather than an attack + on the software itself. User agents may be able to reduce the impact + of such attacks by distinguishing the various components of the URI + when they are rendered, such as by using a different color or tone to + render userinfo if any is present, though there is no panacea. More + information on URI-based semantic attacks can be found in [Siedzik]. + +8. IANA Considerations + + URI scheme names, as defined by <scheme> in Section 3.1, form a + registered namespace that is managed by IANA according to the + procedures defined in [BCP35]. No IANA actions are required by this + document. + +9. Acknowledgements + + This specification is derived from RFC 2396 [RFC2396], RFC 1808 + [RFC1808], and RFC 1738 [RFC1738]; the acknowledgements in those + documents still apply. It also incorporates the update (with + corrections) for IPv6 literals in the host syntax, as defined by + Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in + [RFC2732]. In addition, contributions by Gisle Aas, Reese Anschultz, + Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll, + Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin + Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond, + Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael + Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew + Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert, + Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai + Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne, + Stuart Williams, and Henry Zongaro are gratefully acknowledged. + +10. References + +10.1. Normative References + + [ASCII] American National Standards Institute, "Coded Character + Set -- 7-bit American Standard Code for Information + Interchange", ANSI X3.4, 1986. + + + + + +Berners-Lee, et al. Standards Track [Page 46] + +RFC 3986 URI Generic Syntax January 2005 + + + [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", RFC 2234, November 1997. + + [STD63] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", STD 63, RFC 3629, November 2003. + + [UCS] International Organization for Standardization, + "Information Technology - Universal Multiple-Octet Coded + Character Set (UCS)", ISO/IEC 10646:2003, December 2003. + +10.2. Informative References + + [BCP19] Freed, N. and J. Postel, "IANA Charset Registration + Procedures", BCP 19, RFC 2978, October 2000. + + [BCP35] Petke, R. and I. King, "Registration Procedures for URL + Scheme Names", BCP 35, RFC 2717, November 1999. + + [RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, "DoD Internet + host table specification", RFC 952, October 1985. + + [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", + STD 13, RFC 1034, November 1987. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - Application + and Support", STD 3, RFC 1123, October 1989. + + [RFC1535] Gavron, E., "A Security Problem and Proposed Correction + With Widely Deployed DNS Software", RFC 1535, + October 1993. + + [RFC1630] Berners-Lee, T., "Universal Resource Identifiers in WWW: A + Unifying Syntax for the Expression of Names and Addresses + of Objects on the Network as used in the World-Wide Web", + RFC 1630, June 1994. + + [RFC1736] Kunze, J., "Functional Recommendations for Internet + Resource Locators", RFC 1736, February 1995. + + [RFC1737] Sollins, K. and L. Masinter, "Functional Requirements for + Uniform Resource Names", RFC 1737, December 1994. + + [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform + Resource Locators (URL)", RFC 1738, December 1994. + + [RFC1808] Fielding, R., "Relative Uniform Resource Locators", + RFC 1808, June 1995. + + + + +Berners-Lee, et al. Standards Track [Page 47] + +RFC 3986 URI Generic Syntax January 2005 + + + [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types", RFC 2046, + November 1996. + + [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997. + + [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform + Resource Identifiers (URI): Generic Syntax", RFC 2396, + August 1998. + + [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. + Jensen, "HTTP Extensions for Distributed Authoring -- + WEBDAV", RFC 2518, February 1999. + + [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME + Encapsulation of Aggregate Documents, such as HTML + (MHTML)", RFC 2557, March 1999. + + [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke, + "Guidelines for new URL Schemes", RFC 2718, November 1999. + + [RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for + Literal IPv6 Addresses in URL's", RFC 2732, December 1999. + + [RFC3305] Mealling, M. and R. Denenberg, "Report from the Joint + W3C/IETF URI Planning Interest Group: Uniform Resource + Identifiers (URIs), URLs, and Uniform Resource Names + (URNs): Clarifications and Recommendations", RFC 3305, + August 2002. + + [RFC3490] Faltstrom, P., Hoffman, P., and A. Costello, + "Internationalizing Domain Names in Applications (IDNA)", + RFC 3490, March 2003. + + [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6 + (IPv6) Addressing Architecture", RFC 3513, April 2003. + + [Siedzik] Siedzik, R., "Semantic Attacks: What's in a URL?", + April 2001, <http://www.giac.org/practical/gsec/ + Richard_Siedzik_GSEC.pdf>. + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 48] + +RFC 3986 URI Generic Syntax January 2005 + + +Appendix A. Collected ABNF for URI + + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + URI-reference = URI / relative-ref + + absolute-URI = scheme ":" hier-part [ "?" query ] + + relative-ref = relative-part [ "?" query ] [ "#" fragment ] + + relative-part = "//" authority path-abempty + / path-absolute + / path-noscheme + / path-empty + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + authority = [ userinfo "@" ] host [ ":" port ] + userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + host = IP-literal / IPv4address / reg-name + port = *DIGIT + + IP-literal = "[" ( IPv6address / IPvFuture ) "]" + + IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + + IPv6address = 6( h16 ":" ) ls32 + / "::" 5( h16 ":" ) ls32 + / [ h16 ] "::" 4( h16 ":" ) ls32 + / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + / [ *4( h16 ":" ) h16 ] "::" ls32 + / [ *5( h16 ":" ) h16 ] "::" h16 + / [ *6( h16 ":" ) h16 ] "::" + + h16 = 1*4HEXDIG + ls32 = ( h16 ":" h16 ) / IPv4address + IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + + + + + + + +Berners-Lee, et al. Standards Track [Page 49] + +RFC 3986 URI Generic Syntax January 2005 + + + dec-octet = DIGIT ; 0-9 + / %x31-39 DIGIT ; 10-99 + / "1" 2DIGIT ; 100-199 + / "2" %x30-34 DIGIT ; 200-249 + / "25" %x30-35 ; 250-255 + + reg-name = *( unreserved / pct-encoded / sub-delims ) + + path = path-abempty ; begins with "/" or is empty + / path-absolute ; begins with "/" but not "//" + / path-noscheme ; begins with a non-colon segment + / path-rootless ; begins with a segment + / path-empty ; zero characters + + path-abempty = *( "/" segment ) + path-absolute = "/" [ segment-nz *( "/" segment ) ] + path-noscheme = segment-nz-nc *( "/" segment ) + path-rootless = segment-nz *( "/" segment ) + path-empty = 0<pchar> + + segment = *pchar + segment-nz = 1*pchar + segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + ; non-zero-length segment without any colon ":" + + pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + + query = *( pchar / "/" / "?" ) + + fragment = *( pchar / "/" / "?" ) + + pct-encoded = "%" HEXDIG HEXDIG + + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + reserved = gen-delims / sub-delims + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + +Appendix B. Parsing a URI Reference with a Regular Expression + + As the "first-match-wins" algorithm is identical to the "greedy" + disambiguation method used by POSIX regular expressions, it is + natural and commonplace to use a regular expression for parsing the + potential five components of a URI reference. + + The following line is the regular expression for breaking-down a + well-formed URI reference into its components. + + + +Berners-Lee, et al. Standards Track [Page 50] + +RFC 3986 URI Generic Syntax January 2005 + + + ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? + 12 3 4 5 6 7 8 9 + + The numbers in the second line above are only to assist readability; + they indicate the reference points for each subexpression (i.e., each + paired parenthesis). We refer to the value matched for subexpression + <n> as $<n>. For example, matching the above expression to + + http://www.ics.uci.edu/pub/ietf/uri/#Related + + results in the following subexpression matches: + + $1 = http: + $2 = http + $3 = //www.ics.uci.edu + $4 = www.ics.uci.edu + $5 = /pub/ietf/uri/ + $6 = <undefined> + $7 = <undefined> + $8 = #Related + $9 = Related + + where <undefined> indicates that the component is not present, as is + the case for the query component in the above example. Therefore, we + can determine the value of the five components as + + scheme = $2 + authority = $4 + path = $5 + query = $7 + fragment = $9 + + Going in the opposite direction, we can recreate a URI reference from + its components by using the algorithm of Section 5.3. + +Appendix C. Delimiting a URI in Context + + URIs are often transmitted through formats that do not provide a + clear context for their interpretation. For example, there are many + occasions when a URI is included in plain text; examples include text + sent in email, USENET news, and on printed paper. In such cases, it + is important to be able to delimit the URI from the rest of the text, + and in particular from punctuation marks that might be mistaken for + part of the URI. + + In practice, URIs are delimited in a variety of ways, but usually + within double-quotes "http://example.com/", angle brackets + <http://example.com/>, or just by using whitespace: + + + +Berners-Lee, et al. Standards Track [Page 51] + +RFC 3986 URI Generic Syntax January 2005 + + + http://example.com/ + + These wrappers do not form part of the URI. + + In some cases, extra whitespace (spaces, line-breaks, tabs, etc.) may + have to be added to break a long URI across lines. The whitespace + should be ignored when the URI is extracted. + + No whitespace should be introduced after a hyphen ("-") character. + Because some typesetters and printers may (erroneously) introduce a + hyphen at the end of line when breaking it, the interpreter of a URI + containing a line break immediately after a hyphen should ignore all + whitespace around the line break and should be aware that the hyphen + may or may not actually be part of the URI. + + Using <> angle brackets around each URI is especially recommended as + a delimiting style for a reference that contains embedded whitespace. + + The prefix "URL:" (with or without a trailing space) was formerly + recommended as a way to help distinguish a URI from other bracketed + designators, though it is not commonly used in practice and is no + longer recommended. + + For robustness, software that accepts user-typed URI should attempt + to recognize and strip both delimiters and embedded whitespace. + + For example, the text + + Yes, Jim, I found it under "http://www.w3.org/Addressing/", + but you can probably pick it up from <ftp://foo.example. + com/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/ + ietf/uri/historical.html#WARNING>. + + contains the URI references + + http://www.w3.org/Addressing/ + ftp://foo.example.com/rfc/ + http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 52] + +RFC 3986 URI Generic Syntax January 2005 + + +Appendix D. Changes from RFC 2396 + +D.1. Additions + + An ABNF rule for URI has been introduced to correspond to one common + usage of the term: an absolute URI with optional fragment. + + IPv6 (and later) literals have been added to the list of possible + identifiers for the host portion of an authority component, as + described by [RFC2732], with the addition of "[" and "]" to the + reserved set and a version flag to anticipate future versions of IP + literals. Square brackets are now specified as reserved within the + authority component and are not allowed outside their use as + delimiters for an IP literal within host. In order to make this + change without changing the technical definition of the path, query, + and fragment components, those rules were redefined to directly + specify the characters allowed. + + As [RFC2732] defers to [RFC3513] for definition of an IPv6 literal + address, which, unfortunately, lacks an ABNF description of + IPv6address, we created a new ABNF rule for IPv6address that matches + the text representations defined by Section 2.2 of [RFC3513]. + Likewise, the definition of IPv4address has been improved in order to + limit each decimal octet to the range 0-255. + + Section 6, on URI normalization and comparison, has been completely + rewritten and extended by using input from Tim Bray and discussion + within the W3C Technical Architecture Group. + +D.2. Modifications + + The ad-hoc BNF syntax of RFC 2396 has been replaced with the ABNF of + [RFC2234]. This change required all rule names that formerly + included underscore characters to be renamed with a dash instead. In + addition, a number of syntax rules have been eliminated or simplified + to make the overall grammar more comprehensible. Specifications that + refer to the obsolete grammar rules may be understood by replacing + those rules according to the following table: + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 53] + +RFC 3986 URI Generic Syntax January 2005 + + + +----------------+--------------------------------------------------+ + | obsolete rule | translation | + +----------------+--------------------------------------------------+ + | absoluteURI | absolute-URI | + | relativeURI | relative-part [ "?" query ] | + | hier_part | ( "//" authority path-abempty / | + | | path-absolute ) [ "?" query ] | + | | | + | opaque_part | path-rootless [ "?" query ] | + | net_path | "//" authority path-abempty | + | abs_path | path-absolute | + | rel_path | path-rootless | + | rel_segment | segment-nz-nc | + | reg_name | reg-name | + | server | authority | + | hostport | host [ ":" port ] | + | hostname | reg-name | + | path_segments | path-abempty | + | param | *<pchar excluding ";"> | + | | | + | uric | unreserved / pct-encoded / ";" / "?" / ":" | + | | / "@" / "&" / "=" / "+" / "$" / "," / "/" | + | | | + | uric_no_slash | unreserved / pct-encoded / ";" / "?" / ":" | + | | / "@" / "&" / "=" / "+" / "$" / "," | + | | | + | mark | "-" / "_" / "." / "!" / "~" / "*" / "'" | + | | / "(" / ")" | + | | | + | escaped | pct-encoded | + | hex | HEXDIG | + | alphanum | ALPHA / DIGIT | + +----------------+--------------------------------------------------+ + + Use of the above obsolete rules for the definition of scheme-specific + syntax is deprecated. + + Section 2, on characters, has been rewritten to explain what + characters are reserved, when they are reserved, and why they are + reserved, even when they are not used as delimiters by the generic + syntax. The mark characters that are typically unsafe to decode, + including the exclamation mark ("!"), asterisk ("*"), single-quote + ("'"), and open and close parentheses ("(" and ")"), have been moved + to the reserved set in order to clarify the distinction between + reserved and unreserved and, hopefully, to answer the most common + question of scheme designers. Likewise, the section on + percent-encoded characters has been rewritten, and URI normalizers + are now given license to decode any percent-encoded octets + + + +Berners-Lee, et al. Standards Track [Page 54] + +RFC 3986 URI Generic Syntax January 2005 + + + corresponding to unreserved characters. In general, the terms + "escaped" and "unescaped" have been replaced with "percent-encoded" + and "decoded", respectively, to reduce confusion with other forms of + escape mechanisms. + + The ABNF for URI and URI-reference has been redesigned to make them + more friendly to LALR parsers and to reduce complexity. As a result, + the layout form of syntax description has been removed, along with + the uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path, + path_segments, rel_segment, and mark rules. All references to + "opaque" URIs have been replaced with a better description of how the + path component may be opaque to hierarchy. The relativeURI rule has + been replaced with relative-ref to avoid unnecessary confusion over + whether they are a subset of URI. The ambiguity regarding the + parsing of URI-reference as a URI or a relative-ref with a colon in + the first segment has been eliminated through the use of five + separate path matching rules. + + The fragment identifier has been moved back into the section on + generic syntax components and within the URI and relative-ref rules, + though it remains excluded from absolute-URI. The number sign ("#") + character has been moved back to the reserved set as a result of + reintegrating the fragment syntax. + + The ABNF has been corrected to allow the path component to be empty. + This also allows an absolute-URI to consist of nothing after the + "scheme:", as is present in practice with the "dav:" namespace + [RFC2518] and with the "about:" scheme used internally by many WWW + browser implementations. The ambiguity regarding the boundary + between authority and path has been eliminated through the use of + five separate path matching rules. + + Registry-based naming authorities that use the generic syntax are now + defined within the host rule. This change allows current + implementations, where whatever name provided is simply fed to the + local name resolution mechanism, to be consistent with the + specification. It also removes the need to re-specify DNS name + formats here. Furthermore, it allows the host component to contain + percent-encoded octets, which is necessary to enable + internationalized domain names to be provided in URIs, processed in + their native character encodings at the application layers above URI + processing, and passed to an IDNA library as a registered name in the + UTF-8 character encoding. The server, hostport, hostname, + domainlabel, toplabel, and alphanum rules have been removed. + + The resolving relative references algorithm of [RFC2396] has been + rewritten with pseudocode for this revision to improve clarity and + fix the following issues: + + + +Berners-Lee, et al. Standards Track [Page 55] + +RFC 3986 URI Generic Syntax January 2005 + + + o [RFC2396] section 5.2, step 6a, failed to account for a base URI + with no path. + + o Restored the behavior of [RFC1808] where, if the reference + contains an empty path and a defined query component, the target + URI inherits the base URI's path component. + + o The determination of whether a URI reference is a same-document + reference has been decoupled from the URI parser, simplifying the + URI processing interface within applications in a way consistent + with the internal architecture of deployed URI processing + implementations. The determination is now based on comparison to + the base URI after transforming a reference to absolute form, + rather than on the format of the reference itself. This change + may result in more references being considered "same-document" + under this specification than there would be under the rules given + in RFC 2396, especially when normalization is used to reduce + aliases. However, it does not change the status of existing + same-document references. + + o Separated the path merge routine into two routines: merge, for + describing combination of the base URI path with a relative-path + reference, and remove_dot_segments, for describing how to remove + the special "." and ".." segments from a composed path. The + remove_dot_segments algorithm is now applied to all URI reference + paths in order to match common implementations and to improve the + normalization of URIs in practice. This change only impacts the + parsing of abnormal references and same-scheme references wherein + the base URI has a non-hierarchical path. + +Index + + A + ABNF 11 + absolute 27 + absolute-path 26 + absolute-URI 27 + access 9 + authority 17, 18 + + B + base URI 28 + + C + character encoding 4 + character 4 + characters 8, 11 + coded character set 4 + + + +Berners-Lee, et al. Standards Track [Page 56] + +RFC 3986 URI Generic Syntax January 2005 + + + D + dec-octet 20 + dereference 9 + dot-segments 23 + + F + fragment 16, 24 + + G + gen-delims 13 + generic syntax 6 + + H + h16 20 + hier-part 16 + hierarchical 10 + host 18 + + I + identifier 5 + IP-literal 19 + IPv4 20 + IPv4address 19, 20 + IPv6 19 + IPv6address 19, 20 + IPvFuture 19 + + L + locator 7 + ls32 20 + + M + merge 32 + + N + name 7 + network-path 26 + + P + path 16, 22, 26 + path-abempty 22 + path-absolute 22 + path-empty 22 + path-noscheme 22 + path-rootless 22 + path-abempty 16, 22, 26 + path-absolute 16, 22, 26 + path-empty 16, 22, 26 + + + +Berners-Lee, et al. Standards Track [Page 57] + +RFC 3986 URI Generic Syntax January 2005 + + + path-rootless 16, 22 + pchar 23 + pct-encoded 12 + percent-encoding 12 + port 22 + + Q + query 16, 23 + + R + reg-name 21 + registered name 20 + relative 10, 28 + relative-path 26 + relative-ref 26 + remove_dot_segments 33 + representation 9 + reserved 12 + resolution 9, 28 + resource 5 + retrieval 9 + + S + same-document 27 + sameness 9 + scheme 16, 17 + segment 22, 23 + segment-nz 23 + segment-nz-nc 23 + sub-delims 13 + suffix 27 + + T + transcription 8 + + U + uniform 4 + unreserved 13 + URI grammar + absolute-URI 27 + ALPHA 11 + authority 18 + CR 11 + dec-octet 20 + DIGIT 11 + DQUOTE 11 + fragment 24 + gen-delims 13 + + + +Berners-Lee, et al. Standards Track [Page 58] + +RFC 3986 URI Generic Syntax January 2005 + + + h16 20 + HEXDIG 11 + hier-part 16 + host 19 + IP-literal 19 + IPv4address 20 + IPv6address 20 + IPvFuture 19 + LF 11 + ls32 20 + OCTET 11 + path 22 + path-abempty 22 + path-absolute 22 + path-empty 22 + path-noscheme 22 + path-rootless 22 + pchar 23 + pct-encoded 12 + port 22 + query 24 + reg-name 21 + relative-ref 26 + reserved 13 + scheme 17 + segment 23 + segment-nz 23 + segment-nz-nc 23 + SP 11 + sub-delims 13 + unreserved 13 + URI 16 + URI-reference 25 + userinfo 18 + URI 16 + URI-reference 25 + URL 7 + URN 7 + userinfo 18 + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 59] + +RFC 3986 URI Generic Syntax January 2005 + + +Authors' Addresses + + Tim Berners-Lee + World Wide Web Consortium + Massachusetts Institute of Technology + 77 Massachusetts Avenue + Cambridge, MA 02139 + USA + + Phone: +1-617-253-5702 + Fax: +1-617-258-5999 + EMail: [email protected] + URI: http://www.w3.org/People/Berners-Lee/ + + + Roy T. Fielding + Day Software + 5251 California Ave., Suite 110 + Irvine, CA 92617 + USA + + Phone: +1-949-679-2960 + Fax: +1-949-679-2972 + EMail: [email protected] + URI: http://roy.gbiv.com/ + + + Larry Masinter + Adobe Systems Incorporated + 345 Park Ave + San Jose, CA 95110 + USA + + Phone: +1-408-536-3024 + EMail: [email protected] + URI: http://larry.masinter.net/ + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 60] + +RFC 3986 URI Generic Syntax January 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the IETF's procedures with respect to rights in IETF Documents can + be found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + +Berners-Lee, et al. Standards Track [Page 61] + diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile index e4cb0c4e48..82f2a5829f 100644 --- a/lib/inets/doc/src/Makefile +++ b/lib/inets/doc/src/Makefile @@ -26,16 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include ../../vsn.mk VSN=$(INETS_VSN) - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - - # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -98,37 +88,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = \ - $(XML_PART_FILES:%.xml=%.tex) \ - $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_REF6_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -TOP_HTML_FILES = - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -141,8 +104,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man ldocs: local_docs @@ -156,33 +117,6 @@ html: gifs $(HTML_REF_MAN_FILE) clean clean_docs: clean_html clean_man clean_pdf rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(TOP_HTML_FILES) gifs - -clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - -clean: clean_tex clean_html clean_man - rm -f *.xmls_output *.xmls_errs - rm -f $(TOP_PDF_FILE) - rm -f errs core *~ -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -204,10 +138,7 @@ clean_man: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs - @echo "release_docs_spec(docs) when DOCSUPPORT=$DOCSUPPORT" $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf $(INSTALL_DIR) $(RELSYSDIR)/doc/html @@ -215,33 +146,6 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - @echo "release_docs_spec(pdf)" - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - @echo "release_docs_spec(ps)" - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - @echo "release_docs_spec(docs)" - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: diff --git a/lib/inets/doc/src/ftp.xml b/lib/inets/doc/src/ftp.xml index ca902d8d9d..f8f11ec705 100644 --- a/lib/inets/doc/src/ftp.xml +++ b/lib/inets/doc/src/ftp.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -141,11 +141,21 @@ <tag>{timeout, Timeout}</tag> <item> <marker id="timeout"></marker> - <p>Timeout = <c>integer() >= 0</c> </p> + <p>Timeout = <c>non_neg_integer()</c> </p> <p>Connection timeout. </p> <p>Default is 60000 (milliseconds). </p> </item> + <tag>{dtimeout, DTimeout}</tag> + <item> + <marker id="dtimeout"></marker> + <p>DTimeout = <c>non_neg_integer() | infinity</c> </p> + <p>Data Connect timeout. + The time the client will wait for the server to connect to the + data socket. </p> + <p>Default is infinity. </p> + </item> + <tag>{progress, Progress}</tag> <item> <marker id="progress"></marker> @@ -542,11 +552,12 @@ <v>verbose() = boolean() (defaults to false)</v> <v>debug() = disable | debug | trace (defaults to disable)</v> <!-- <v>open_options() = [open_option()]</v> --> - <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {timeout, timeout()} | {progress, progress()}</v> + <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress()}</v> <v>ipfamily() = inet | inet6 | inet6fb4 (defaults to inet)</v> <v>port() = integer() > 0 (defaults to 21)</v> <v>mode() = active | passive (defaults to passive)</v> - <v>timeout() = integer() >= 0 (defaults to 60000 milliseconds)</v> + <v>timeout() = integer() > 0 (defaults to 60000 milliseconds)</v> + <v>dtimeout() = integer() > 0 | infinity (defaults to infinity)</v> <v>pogress() = ignore | {module(), function(), initial_data()} (defaults to ignore)</v> <v>module() = atom()</v> <v>function() = atom()</v> diff --git a/lib/inets/doc/src/make.dep b/lib/inets/doc/src/make.dep deleted file mode 100644 index 8deb7e7a5a..0000000000 --- a/lib/inets/doc/src/make.dep +++ /dev/null @@ -1,47 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2010. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# 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 online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# - -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex ftp.tex ftp_client.tex httpc.tex http_client.tex \ - http_server.tex httpd.tex httpd_conf.tex httpd_socket.tex \ - httpd_util.tex inets.tex inets_services.tex \ - mod_alias.tex mod_auth.tex mod_esi.tex mod_security.tex \ - part.tex ref_man.tex tftp.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -ftp.tex: ../../../../system/doc/definitions/term.defs - -inets_services.tex: ../../../../system/doc/definitions/term.defs - diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 87a8c173a5..7f0f61148c 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -35,30 +35,78 @@ <section><title>Inets 5.8</title> <section><title>Improvements and New Features</title> +<!-- <p>-</p> +--> + <list> + <item> + <p>[ftpc] Add a config option to specify a + <seealso marker="ftp#dtimeout">data connect timeout</seealso>. + That is how long the ftp client will wait for the server to connect + to the data socket. If this timeout occurs, an error will be + returned to the caller and the ftp client process will be + terminated. </p> + <p>Own Id: OTP-9545</p> + </item> + + </list> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> <!-- + <p>-</p> +--> + <list> <item> - <p>[httpc|httpd] Added support for IPv6 with ssl. </p> - <p>Own Id: OTP-5566</p> + <p>[httpd] Fix logging of content length in mod_log. </p> + <p>Garrett Smith</p> + <p>Own Id: OTP-9715</p> </item> </list> + + </section> + + <section> + <title>Incompatibilities</title> +<!-- + <p>-</p> --> + <list> + <item> + <p>[httpc] Deprecated interface module <c>http</c> has been removed. + It has (long) been replaced by http client interface module + <seealso marker="httpc#">httpc</seealso>. </p> + <p>Own Id: OTP-9359</p> + </item> + + <item> + <p>[httpc|httpd] The old ssl implementation (based on OpenSSL), + has been deprecated. The config option that specified usage of + this version of the ssl app, <c>ossl</c>, has been removed. </p> + <p>Own Id: OTP-9522</p> + </item> + + </list> + </section> - <section><title>Fixed Bugs and Malfunctions</title> + </section> <!-- 5.8 --> + + + <section><title>Inets 5.7.2</title> + <section><title>Improvements and New Features</title> <p>-</p> <!-- <list> <item> - <p>[httpc] Remove unnecessary usage of iolist_to_binary when - processing body (for PUT and POST). </p> - <p>Filipe David Manana</p> - <p>Own Id: OTP-9317</p> + <p>[httpc|httpd] Added support for IPv6 with ssl. </p> + <p>Own Id: OTP-5566</p> </item> </list> @@ -91,9 +139,31 @@ </section> - </section> <!-- 5.8 --> + <section><title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + <list> + <item> + <p>[httpd] XSS prevention did not work for hex-encoded URL's. </p> + <p>Own Id: OTP-9655</p> + </item> + + <item> + <p>[httpd] GET request with malformed header date caused + server crash (non-fatal) with no reply to client. Will + now result in a reply with status code 400. </p> + <p>Own Id: OTP-9674</p> + <p>Aux Id: seq11936</p> + </item> + + </list> + </section> + </section> <!-- 5.7.2 --> + + <section><title>Inets 5.7.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index ac72963347..b6da92947c 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -55,9 +55,10 @@ -include("ftp_internal.hrl"). %% Constante used in internal state definition --define(CONNECTION_TIMEOUT, 60*1000). --define(DEFAULT_MODE, passive). --define(PROGRESS_DEFAULT, ignore). +-define(CONNECTION_TIMEOUT, 60*1000). +-define(DATA_ACCEPT_TIMEOUT, infinity). +-define(DEFAULT_MODE, passive). +-define(PROGRESS_DEFAULT, ignore). %% Internal Constants -define(FTP_PORT, 21). @@ -88,7 +89,8 @@ %% data needed further on. caller = undefined, % term() ipfamily, % inet | inet6 | inet6fb4 - progress = ignore % ignore | pid() + progress = ignore, % ignore | pid() + dtimeout = ?DATA_ACCEPT_TIMEOUT % non_neg_integer() | infinity }). @@ -847,6 +849,7 @@ start_options(Options) -> %% host %% port %% timeout +%% dtimeout %% progress open_options(Options) -> ?fcrt("open_options", [{options, Options}]), @@ -875,7 +878,12 @@ open_options(Options) -> (_) -> false end, ValidateTimeout = - fun(Timeout) when is_integer(Timeout) andalso (Timeout > 0) -> true; + fun(Timeout) when is_integer(Timeout) andalso (Timeout >= 0) -> true; + (_) -> false + end, + ValidateDTimeout = + fun(DTimeout) when is_integer(DTimeout) andalso (DTimeout >= 0) -> true; + (infinity) -> true; (_) -> false end, ValidateProgress = @@ -893,6 +901,7 @@ open_options(Options) -> {port, ValidatePort, false, ?FTP_PORT}, {ipfamily, ValidateIpFamily, false, inet}, {timeout, ValidateTimeout, false, ?CONNECTION_TIMEOUT}, + {dtimeout, ValidateDTimeout, false, ?DATA_ACCEPT_TIMEOUT}, {progress, ValidateProgress, false, ?PROGRESS_DEFAULT}], validate_options(Options, ValidOptions, []). @@ -1037,13 +1046,15 @@ handle_call({_, {open, ip_comm, Opts}}, From, State) -> Mode = key_search(mode, Opts, ?DEFAULT_MODE), Port = key_search(port, Opts, ?FTP_PORT), Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT), + DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT), Progress = key_search(progress, Opts, ignore), IpFamily = key_search(ipfamily, Opts, inet), - + State2 = State#state{client = From, mode = Mode, progress = progress(Progress), - ipfamily = IpFamily}, + ipfamily = IpFamily, + dtimeout = DTimeout}, ?fcrd("handle_call(open) -> setup ctrl connection with", [{host, Host}, {port, Port}, {timeout, Timeout}]), @@ -1064,11 +1075,13 @@ handle_call({_, {open, ip_comm, Host, Opts}}, From, State) -> Mode = key_search(mode, Opts, ?DEFAULT_MODE), Port = key_search(port, Opts, ?FTP_PORT), Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT), + DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT), Progress = key_search(progress, Opts, ignore), State2 = State#state{client = From, mode = Mode, - progress = progress(Progress)}, + progress = progress(Progress), + dtimeout = DTimeout}, case setup_ctrl_connection(Host, Port, Timeout, State2) of {ok, State3, WaitTimeout} -> @@ -1657,9 +1670,19 @@ handle_ctrl_result({pos_compl, Lines}, %%-------------------------------------------------------------------------- %% Directory listing handle_ctrl_result({pos_prel, _}, #state{caller = {dir, Dir}} = State) -> - NewState = accept_data_connection(State), - activate_data_connection(NewState), - {noreply, NewState#state{caller = {handle_dir_result, Dir}}}; + case accept_data_connection(State) of + {ok, NewState} -> + activate_data_connection(NewState), + {noreply, NewState#state{caller = {handle_dir_result, Dir}}}; + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; handle_ctrl_result({pos_compl, _}, #state{caller = {handle_dir_result, Dir, Data}, client = From} @@ -1756,9 +1779,19 @@ handle_ctrl_result({Status, _}, %%-------------------------------------------------------------------------- %% File handling - recv_bin handle_ctrl_result({pos_prel, _}, #state{caller = recv_bin} = State) -> - NewState = accept_data_connection(State), - activate_data_connection(NewState), - {noreply, NewState}; + case accept_data_connection(State) of + {ok, NewState} -> + activate_data_connection(NewState), + {noreply, NewState}; + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; handle_ctrl_result({pos_compl, _}, #state{caller = {recv_bin, Data}, client = From} = State) -> @@ -1780,16 +1813,37 @@ handle_ctrl_result({Status, _}, #state{caller = {recv_bin, _}} = State) -> handle_ctrl_result({pos_prel, _}, #state{client = From, caller = start_chunk_transfer} = State) -> - NewState = accept_data_connection(State), - gen_server:reply(From, ok), - {noreply, NewState#state{chunk = true, client = undefined, - caller = undefined}}; + case accept_data_connection(State) of + {ok, NewState} -> + gen_server:reply(From, ok), + {noreply, NewState#state{chunk = true, client = undefined, + caller = undefined}}; + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; + %%-------------------------------------------------------------------------- %% File handling - recv_file handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State) -> - NewState = accept_data_connection(State), - activate_data_connection(NewState), - {noreply, NewState}; + case accept_data_connection(State) of + {ok, NewState} -> + activate_data_connection(NewState), + {noreply, NewState}; + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) -> file_close(Fd), @@ -1800,17 +1854,38 @@ handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) -> %% File handling - transfer_* handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_file, Fd}} = State) -> - NewState = accept_data_connection(State), - send_file(Fd, NewState); + case accept_data_connection(State) of + {ok, NewState} -> + send_file(Fd, NewState); + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}} = State) -> - NewState = accept_data_connection(State), - send_data_message(NewState, Bin), - close_data_connection(NewState), - activate_ctrl_connection(NewState), - {noreply, NewState#state{caller = transfer_data_second_phase, - dsock = undefined}}; + case accept_data_connection(State) of + {ok, NewState} -> + send_data_message(NewState, Bin), + close_data_connection(NewState), + activate_ctrl_connection(NewState), + {noreply, NewState#state{caller = transfer_data_second_phase, + dsock = undefined}}; + {error, _Reason} = ERROR -> + case State#state.client of + undefined -> + {stop, ERROR, State}; + From -> + gen_server:reply(From, ERROR), + {stop, normal, State#state{client = undefined}} + end + end; + %%-------------------------------------------------------------------------- %% Default handle_ctrl_result({Status, Lines}, #state{client = From} = State) @@ -2009,16 +2084,20 @@ connect2(Host, Port, IpFam, Timeout) -> Error end. - -accept_data_connection(#state{mode = active, - dsock = {lsock, LSock}} = State) -> - {ok, Socket} = gen_tcp:accept(LSock), - gen_tcp:close(LSock), - State#state{dsock = Socket}; +accept_data_connection(#state{mode = active, + dtimeout = DTimeout, + dsock = {lsock, LSock}} = State) -> + case gen_tcp:accept(LSock, DTimeout) of + {ok, Socket} -> + gen_tcp:close(LSock), + {ok, State#state{dsock = Socket}}; + {error, Reason} -> + {error, {data_connect_failed, Reason}} + end; accept_data_connection(#state{mode = passive} = State) -> - State. + {ok, State}. send_ctrl_message(#state{csock = Socket, verbose = Verbose}, Message) -> %% io:format("send control message: ~n~p~n", [lists:flatten(Message)]), diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 75c26c63cc..d72c34fa6b 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -141,7 +141,9 @@ request(Url, Profile) -> request(Method, Request, HttpOptions, Options) -> request(Method, Request, HttpOptions, Options, default_profile()). -request(Method, {Url, Headers}, HTTPOptions, Options, Profile) +request(Method, + {Url, Headers}, + HTTPOptions, Options, Profile) when (Method =:= options) orelse (Method =:= get) orelse (Method =:= head) orelse @@ -154,15 +156,17 @@ request(Method, {Url, Headers}, HTTPOptions, Options, Profile) {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url) of + case http_uri:parse(Url, Options) of {error, Reason} -> {error, Reason}; - ParsedUrl -> + {ok, ParsedUrl} -> handle_request(Method, Url, ParsedUrl, Headers, [], [], HTTPOptions, Options, Profile) end; -request(Method, {Url,Headers,ContentType,Body}, HTTPOptions, Options, Profile) +request(Method, + {Url, Headers, ContentType, Body}, + HTTPOptions, Options, Profile) when ((Method =:= post) orelse (Method =:= put)) andalso (is_atom(Profile) orelse is_pid(Profile)) -> ?hcrt("request", [{method, Method}, @@ -173,10 +177,10 @@ request(Method, {Url,Headers,ContentType,Body}, HTTPOptions, Options, Profile) {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url) of + case http_uri:parse(Url, Options) of {error, Reason} -> {error, Reason}; - ParsedUrl -> + {ok, ParsedUrl} -> handle_request(Method, Url, ParsedUrl, Headers, ContentType, Body, HTTPOptions, Options, Profile) @@ -267,7 +271,10 @@ store_cookies(SetCookieHeaders, Url, Profile) {profile, Profile}]), try begin - {_, _, Host, Port, Path, _} = http_uri:parse(Url), + %% Since the Address part is not actually used + %% by the manager when storing cookies, we dont + %% care about ipv6-host-with-brackets. + {ok, {_, _, Host, Port, Path, _}} = http_uri:parse(Url), Address = {Host, Port}, ProfileName = profile_name(Profile), Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host), @@ -464,6 +471,8 @@ handle_request(Method, Url, HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions), Receiver = proplists:get_value(receiver, Options), SocketOpts = proplists:get_value(socket_opts, Options), + BracketedHost = proplists:get_value(ipv6_host_with_brackets, + Options), MaybeEscPath = maybe_encode_uri(HTTPOptions, Path), MaybeEscQuery = maybe_encode_uri(HTTPOptions, Query), AbsUri = maybe_encode_uri(HTTPOptions, Url), @@ -482,7 +491,8 @@ handle_request(Method, Url, stream = Stream, headers_as_is = headers_as_is(Headers0, Options), socket_opts = SocketOpts, - started = Started}, + started = Started, + ipv6_host_with_brackets = BracketedHost}, case httpc_manager:request(Request, profile_name(Profile)) of {ok, RequestId} -> @@ -739,14 +749,17 @@ request_options_defaults() -> error end, + VerifyBrackets = VerifyBoolean, + [ - {sync, true, VerifySync}, - {stream, none, VerifyStream}, - {body_format, string, VerifyBodyFormat}, - {full_result, true, VerifyFullResult}, - {headers_as_is, false, VerifyHeaderAsIs}, - {receiver, self(), VerifyReceiver}, - {socket_opts, undefined, VerifySocketOpts} + {sync, true, VerifySync}, + {stream, none, VerifyStream}, + {body_format, string, VerifyBodyFormat}, + {full_result, true, VerifyFullResult}, + {headers_as_is, false, VerifyHeaderAsIs}, + {receiver, self(), VerifyReceiver}, + {socket_opts, undefined, VerifySocketOpts}, + {ipv6_host_with_brackets, false, VerifyBrackets} ]. request_options(Options) -> diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl index 1d8a5b6a92..e4127d992d 100644 --- a/lib/inets/src/http_client/httpc_internal.hrl +++ b/lib/inets/src/http_client/httpc_internal.hrl @@ -90,25 +90,28 @@ %%% All data associated to a specific HTTP request -record(request, { - id, % ref() - Request Id - from, % pid() - Caller - redircount = 0,% Number of redirects made for this request - scheme, % http | https - address, % ({Host,Port}) Destination Host and Port - path, % string() - Path of parsed URL - pquery, % string() - Rest of parsed URL - method, % atom() - HTTP request Method - headers, % #http_request_h{} - content, % {ContentType, Body} - Current HTTP request - settings, % #http_options{} - User defined settings - abs_uri, % string() ex: "http://www.erlang.org" - userinfo, % string() - optinal "<userinfo>@<host>:<port>" - stream, % Boolean() - stream async reply? - headers_as_is, % Boolean() - workaround for servers that does - % not honor the http standard, can also be used for testing purposes. - started, % integer() > 0 - When we started processing the request - timer, % undefined | ref() - socket_opts % undefined | [socket_option()] + id, % ref() - Request Id + from, % pid() - Caller + redircount = 0,% Number of redirects made for this request + scheme, % http | https + address, % ({Host,Port}) Destination Host and Port + path, % string() - Path of parsed URL + pquery, % string() - Rest of parsed URL + method, % atom() - HTTP request Method + headers, % #http_request_h{} + content, % {ContentType, Body} - Current HTTP request + settings, % #http_options{} - User defined settings + abs_uri, % string() ex: "http://www.erlang.org" + userinfo, % string() - optinal "<userinfo>@<host>:<port>" + stream, % boolean() - stream async reply? + headers_as_is, % boolean() - workaround for servers that does + % not honor the http standard, can also be used + % for testing purposes. + started, % integer() > 0 - When we started processing the + % request + timer, % undefined | ref() + socket_opts, % undefined | [socket_option()] + ipv6_host_with_brackets % boolean() } ). diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 9015bf1ce2..ab575d867e 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -256,19 +256,27 @@ reset_cookies(ProfileName) -> %%-------------------------------------------------------------------- -%% Function: which_cookies(Url, ProfileName) -> [cookie()] +%% Function: which_cookies(ProfileName) -> [cookie()] +%% which_cookies(Url, ProfileName) -> [cookie()] +%% which_cookies(Url, Options, ProfileName) -> [cookie()] %% %% Url = string() +%% Options = [option()] %% ProfileName = atom() +%% option() = {ipv6_host_with_brackets, boolean()} %% %% Description: Retrieves the cookies that would be sent when %% requesting <Url>. %%-------------------------------------------------------------------- -which_cookies(ProfileName) -> +which_cookies(ProfileName) when is_atom(ProfileName) -> call(ProfileName, which_cookies). -which_cookies(Url, ProfileName) -> - call(ProfileName, {which_cookies, Url}). +which_cookies(Url, ProfileName) + when is_list(Url) andalso is_atom(ProfileName) -> + call(ProfileName, {which_cookies, Url, []}). +which_cookies(Url, Options, ProfileName) + when is_list(Url) andalso is_list(Options) andalso is_atom(ProfileName) -> + call(ProfileName, {which_cookies, Url, Options}). %%-------------------------------------------------------------------- @@ -395,15 +403,16 @@ handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) -> CookieHeaders = httpc_cookie:which_cookies(CookieDb), {reply, CookieHeaders, State}; -handle_call({which_cookies, Url}, _, #state{cookie_db = CookieDb} = State) -> - ?hcrv("which cookies", [{url, Url}]), - case http_uri:parse(Url) of - {Scheme, _, Host, Port, Path, _} -> +handle_call({which_cookies, Url, Options}, _, + #state{cookie_db = CookieDb} = State) -> + ?hcrv("which cookies", [{url, Url}, {options, Options}]), + case http_uri:parse(Url, Options) of + {ok, {Scheme, _, Host, Port, Path, _}} -> CookieHeaders = httpc_cookie:header(CookieDb, Scheme, {Host, Port}, Path), {reply, CookieHeaders, State}; - Msg -> - {reply, Msg, State} + {error, _} = ERROR -> + {reply, ERROR, State} end; handle_call(info, _, State) -> diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index 207b96271c..2414ed0911 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -340,7 +340,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) -> undefined -> transparent(Response, Request); RedirUrl -> - case http_uri:parse(RedirUrl) of + UrlParseOpts = [{ipv6_host_with_brackets, + Request#request.ipv6_host_with_brackets}], + case http_uri:parse(RedirUrl, UrlParseOpts) of {error, no_scheme} when (Request#request.settings)#http_options.relaxed -> NewLocation = fix_relative_uri(Request, RedirUrl), @@ -350,10 +352,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) -> {error, Reason} -> {ok, error(Request, Reason), Data}; %% Automatic redirection - {Scheme, _, Host, Port, Path, Query} -> + {ok, {Scheme, _, Host, Port, Path, Query}} -> NewHeaders = - (Request#request.headers)#http_request_h{host = - Host}, + (Request#request.headers)#http_request_h{host = Host}, NewRequest = Request#request{redircount = Request#request.redircount+1, diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 44b9face0b..32c6305a79 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -16,23 +16,30 @@ %% %% %CopyrightEnd% %% -%% +%% +%% RFC 3986 +%% -module(http_uri). --export([parse/1, encode/1, decode/1]). +-export([parse/1, parse/2, + encode/1, decode/1]). + %%%========================================================================= %%% API %%%========================================================================= parse(AbsURI) -> + parse(AbsURI, []). + +parse(AbsURI, Opts) -> case parse_scheme(AbsURI) of {error, Reason} -> {error, Reason}; {Scheme, Rest} -> - case (catch parse_uri_rest(Scheme, Rest)) of + case (catch parse_uri_rest(Scheme, Rest, Opts)) of {UserInfo, Host, Port, Path, Query} -> - {Scheme, UserInfo, Host, Port, Path, Query}; + {ok, {Scheme, UserInfo, Host, Port, Path, Query}}; _ -> {error, {malformed_url, AbsURI}} end @@ -42,35 +49,38 @@ encode(URI) -> Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, $#, $[, $], $<, $>, $\", ${, $}, $|, $\\, $', $^, $%, $ ]), - lists:append(lists:map(fun(Char) -> - uri_encode(Char, Reserved) - end, URI)). - -decode([$%,Hex1,Hex2|Rest]) -> - [hex2dec(Hex1)*16+hex2dec(Hex2)|decode(Rest)]; -decode([First|Rest]) -> - [First|decode(Rest)]; -decode([]) -> + %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)). + lists:append([uri_encode(Char, Reserved) || Char <- URI]). + +decode(String) -> + do_decode(String). + +do_decode([$%,Hex1,Hex2|Rest]) -> + [hex2dec(Hex1)*16+hex2dec(Hex2)|do_decode(Rest)]; +do_decode([First|Rest]) -> + [First|do_decode(Rest)]; +do_decode([]) -> []. + %%%======================================================================== %%% Internal functions %%%======================================================================== + parse_scheme(AbsURI) -> case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of {error, no_scheme} -> {error, no_scheme}; {StrScheme, Rest} -> case list_to_atom(http_util:to_lower(StrScheme)) of - Scheme when Scheme == http; Scheme == https -> + Scheme when (Scheme =:= http) orelse (Scheme =:= https) -> {Scheme, Rest}; Scheme -> {error, {not_supported_scheme, Scheme}} end end. -parse_uri_rest(Scheme, "//" ++ URIPart) -> - +parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> {Authority, PathQuery} = case split_uri(URIPart, "/", URIPart, 1, 0) of Split = {_, _} -> @@ -85,8 +95,8 @@ parse_uri_rest(Scheme, "//" ++ URIPart) -> end, {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1), - {Host, Port} = parse_host_port(Scheme, HostPort), - {Path, Query} = parse_path_query(PathQuery), + {Host, Port} = parse_host_port(Scheme, HostPort, Opts), + {Path, Query} = parse_path_query(PathQuery), {UserInfo, Host, Port, Path, Query}. @@ -94,13 +104,14 @@ parse_path_query(PathQuery) -> {Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0), {path(Path), Query}. -parse_host_port(Scheme,"[" ++ HostPort) -> %ipv6 +parse_host_port(Scheme,"[" ++ HostPort, Opts) -> %ipv6 DefaultPort = default_port(Scheme), {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1), + Host2 = maybe_ipv6_host_with_brackets(Host, Opts), {_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1), - {Host, int_port(Port)}; + {Host2, int_port(Port)}; -parse_host_port(Scheme, HostPort) -> +parse_host_port(Scheme, HostPort, _Opts) -> DefaultPort = default_port(Scheme), {Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1), {Host, int_port(Port)}. @@ -114,6 +125,14 @@ split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) -> NoMatchResult end. +maybe_ipv6_host_with_brackets(Host, Opts) -> + case lists:keysearch(ipv6_host_with_brackets, 1, Opts) of + {value, {ipv6_host_with_brackets, true}} -> + "[" ++ Host ++ "]"; + _ -> + Host + end. + default_port(http) -> 80; default_port(https) -> diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl index 973600d7be..5b21170b78 100644 --- a/lib/inets/src/http_lib/http_util.erl +++ b/lib/inets/src/http_lib/http_util.erl @@ -206,9 +206,7 @@ timeout(Timeout, Started) -> html_encode(Chars) -> Reserved = sets:from_list([$&, $<, $>, $\", $', $/]), - lists:append(lists:map(fun(Char) -> - char_to_html_entity(Char, Reserved) - end, Chars)). + lists:append([char_to_html_entity(Char, Reserved) || Char <- Chars]). %%%======================================================================== diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl index e8a8ab6411..f2ba33099e 100644 --- a/lib/inets/src/http_server/httpd_file.erl +++ b/lib/inets/src/http_server/httpd_file.erl @@ -36,9 +36,9 @@ handle_error(emfile, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": Too many open files"); handle_error({enfile,_}, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": File table overflow"); -handle_error(_Reason, Op, ModData, Path) -> - handle_error(404, Op, ModData, Path, ": File not found"). - +handle_error(_Reason, Op, _ModData, Path) -> + handle_error(500, Op, none, Path, ""). + handle_error(StatusCode, Op, none, Path, Reason) -> {StatusCode, none, ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)}; handle_error(StatusCode, Op, ModData, Path, Reason) -> diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index a04bcc2778..5ba79b2706 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -309,12 +309,12 @@ validate_uri(RequestURI) -> (catch http_uri:decode(string:left(RequestURI, Ndx))) end, case UriNoQueryNoHex of - {'EXIT',_Reason} -> + {'EXIT', _Reason} -> {error, {bad_request, {malformed_syntax, RequestURI}}}; _ -> Path = format_request_uri(UriNoQueryNoHex), - Path2 = [X||X<-string:tokens(Path, "/\\"),X=/="."], - validate_path( Path2,0, RequestURI) + Path2 = [X||X<-string:tokens(Path, "/"),X=/="."], %% OTP-5938 + validate_path(Path2, 0, RequestURI) end. validate_path([], _, _) -> diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index c3b47ce390..d2f22fce93 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1997-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the @@ -355,7 +355,7 @@ handle_http_msg({Method, Uri, Version, {RecordHeaders, Headers}, Body}, Reason = io_lib:format("Forbidden URI: ~p~n", [URI]), error_log(Reason, ModData), {stop, normal, State#state{response_sent = true}}; - {error,{bad_request, {malformed_syntax, URI}}} -> + {error, {bad_request, {malformed_syntax, URI}}} -> ?hdrd("validation failed: bad request - malformed syntax", [{uri, URI}]), httpd_response:send_status(ModData#mod{http_version = Version}, diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index ea9cfbf4f2..dd7223876e 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,6 +78,7 @@ traverse_modules(ModData,[Module|Rest]) -> [Module, Reason])), report_error(mod_log, ModData#mod.config_db, String), report_error(mod_disk_log, ModData#mod.config_db, String), + send_status(ModData, 500, none), done; done -> ?hdrt("traverse modules - done", []), @@ -100,12 +101,19 @@ send_status(#mod{socket_type = SocketType, socket = Socket, config_db = ConfigDB} = ModData, StatusCode, PhraseArgs) -> + ?hdrd("send status", [{status_code, StatusCode}, + {phrase_args, PhraseArgs}]), + ReasonPhrase = httpd_util:reason_phrase(StatusCode), Message = httpd_util:message(StatusCode, PhraseArgs, ConfigDB), Body = get_body(ReasonPhrase, Message), - send_header(ModData, StatusCode, [{content_type, "text/html"}, - {content_length, integer_to_list(length(Body))}]), + ?hdrt("send status - header", [{reason_phrase, ReasonPhrase}, + {message, Message}]), + send_header(ModData, StatusCode, + [{content_type, "text/html"}, + {content_length, integer_to_list(length(Body))}]), + httpd_socket:deliver(SocketType, Socket, Body). @@ -345,8 +353,9 @@ transform({Field, Value}) when is_list(Field) -> %% Leave this method and go on to the newer form of response %% OTP-4408 %%---------------------------------------------------------------------- -send_response_old(#mod{method = "HEAD"} = ModData, +send_response_old(#mod{method = "HEAD"} = ModData, StatusCode, Response) -> + NewResponse = lists:flatten(Response), case httpd_util:split(NewResponse, [?CR, ?LF, ?CR, ?LF],2) of diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index c051422529..b0b18b9c3d 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -178,11 +178,12 @@ message(301,URL,_) -> "The document has moved <A HREF=\""++ maybe_encode(URL) ++"\">here</A>."; message(304, _URL,_) -> "The document has not been changed."; -message(400,none,_) -> - "Your browser sent a query that this server could not understand."; -message(400,Msg,_) -> - "Your browser sent a query that this server could not understand. "++ http_util:html_encode(Msg); -message(401,none,_) -> +message(400, none, _) -> + "Your browser sent a query that this server could not understand. "; +message(400, Msg, _) -> + "Your browser sent a query that this server could not understand. " ++ + html_encode(Msg); +message(401, none, _) -> "This server could not verify that you are authorized to access the document you requested. Either you supplied the wrong @@ -190,40 +191,49 @@ credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required."; message(403,RequestURI,_) -> - "You don't have permission to access "++ http_util:html_encode(RequestURI) ++" on this server."; + "You don't have permission to access " ++ + html_encode(RequestURI) ++ + " on this server."; message(404,RequestURI,_) -> - "The requested URL " ++ http_util:html_encode(RequestURI) ++ " was not found on this server."; + "The requested URL " ++ + html_encode(RequestURI) ++ + " was not found on this server."; message(408, Timeout, _) -> Timeout; message(412,none,_) -> "The requested preconditions were false"; message(413, Reason,_) -> - "Entity: " ++ http_util:html_encode(Reason); + "Entity: " ++ html_encode(Reason); message(414,ReasonPhrase,_) -> - "Message "++ http_util:html_encode(ReasonPhrase) ++"."; + "Message " ++ html_encode(ReasonPhrase) ++ "."; message(416,ReasonPhrase,_) -> - http_util:html_encode(ReasonPhrase); + html_encode(ReasonPhrase); message(500,_,ConfigDB) -> ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"), "The server encountered an internal error or " "misconfiguration and was unable to complete " "your request.<P>Please contact the server administrator " - ++ http_util:html_encode(ServerAdmin) ++ ", and inform them of the time the error occurred " + ++ html_encode(ServerAdmin) ++ + ", and inform them of the time the error occurred " "and anything you might have done that may have caused the error."; message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) -> if is_atom(Method) -> - http_util:html_encode(atom_to_list(Method))++ - " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported."; + atom_to_list(Method) ++ + " to " ++ + html_encode(RequestURI) ++ + " (" ++ HTTPVersion ++ ") not supported."; is_list(Method) -> - http_util:html_encode(Method)++ - " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported." + Method ++ + " to " ++ + html_encode(RequestURI) ++ + " (" ++ HTTPVersion ++ ") not supported." end; message(503, String, _ConfigDB) -> - "This service in unavailable due to: "++ http_util:html_encode(String). + "This service in unavailable due to: " ++ html_encode(String). maybe_encode(URI) -> Decoded = try http_uri:decode(URI) of @@ -233,6 +243,15 @@ maybe_encode(URI) -> end, http_uri:encode(Decoded). +html_encode(String) -> + try http_uri:decode(String) of + Decoded when is_list(Decoded) -> + http_util:html_encode(Decoded) + catch + _:_ -> + http_util:html_encode(String) + end. + %%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}} convert_request_date([D,A,Y,DateType| Rest])-> @@ -245,7 +264,7 @@ convert_request_date([D,A,Y,DateType| Rest])-> fun convert_rfc850_date/1 end, case catch Func([D,A,Y,DateType| Rest]) of - {ok,Date} -> + {ok, Date} -> Date; _Error-> bad_date diff --git a/lib/inets/src/http_server/mod_log.erl b/lib/inets/src/http_server/mod_log.erl index c8a2ec0dc4..62faa285df 100644 --- a/lib/inets/src/http_server/mod_log.erl +++ b/lib/inets/src/http_server/mod_log.erl @@ -100,7 +100,7 @@ do(Info) -> transfer_log(Info,"-",AuthUser,Date,StatusCode,Size), {proceed,Info#mod.data}; {response, Head, _Body} -> - Size = proplists:get_value(content_length,Head,unknown), + Size = content_length(Head), Code = proplists:get_value(code,Head,unknown), transfer_log(Info, "-", AuthUser, Date, Code, Size), {proceed, Info#mod.data}; @@ -254,4 +254,10 @@ auth_user(Data) -> RemoteUser end. - +content_length(Head) -> + case proplists:get_value(content_length, Head) of + undefined -> + unknown; + Size -> + list_to_integer(Size) + end. diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl index 5d5b60cdbd..989f45db20 100644 --- a/lib/inets/src/http_server/mod_responsecontrol.erl +++ b/lib/inets/src/http_server/mod_responsecontrol.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -209,14 +209,14 @@ compare_etags(Tag,Etags) -> nomatch end. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%%Control if the file is modificated %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Control if the file is modificated %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%---------------------------------------------------------------------- -%%Control the If-Modified-Since and If-Not-Modified-Since header fields +%% Control the If-Modified-Since and If-Not-Modified-Since header fields %%---------------------------------------------------------------------- control_modification(Path,Info,FileInfo)-> ?DEBUG("control_modification() -> entry",[]), @@ -227,6 +227,8 @@ control_modification(Path,Info,FileInfo)-> continue; unmodified-> {304, Info, Path}; + {bad_date, _} = BadDate-> + {400, Info, BadDate}; undefined -> case control_modification_data(Info, FileInfo#file_info.mtime, @@ -253,21 +255,27 @@ control_modification_data(Info, ModificationTime, HeaderField)-> undefined-> undefined; LastModified0 -> - LastModified = calendar:universal_time_to_local_time( - httpd_util:convert_request_date(LastModified0)), - ?DEBUG("control_modification_data() -> " - "~n Request-Field: ~s" - "~n FileLastModified: ~p" - "~n FieldValue: ~p", - [HeaderField, ModificationTime, LastModified]), - FileTime = - calendar:datetime_to_gregorian_seconds(ModificationTime), - FieldTime = calendar:datetime_to_gregorian_seconds(LastModified), - if - FileTime =< FieldTime -> - ?DEBUG("File unmodified~n", []), unmodified; - FileTime >= FieldTime -> - ?DEBUG("File modified~n", []), modified + case httpd_util:convert_request_date(LastModified0) of + bad_date -> + {bad_date, LastModified0}; + ConvertedReqDate -> + LastModified = + calendar:universal_time_to_local_time(ConvertedReqDate), + ?DEBUG("control_modification_data() -> " + "~n Request-Field: ~s" + "~n FileLastModified: ~p" + "~n FieldValue: ~p", + [HeaderField, ModificationTime, LastModified]), + FileTime = + calendar:datetime_to_gregorian_seconds(ModificationTime), + FieldTime = + calendar:datetime_to_gregorian_seconds(LastModified), + if + FileTime =< FieldTime -> + ?DEBUG("File unmodified~n", []), unmodified; + FileTime >= FieldTime -> + ?DEBUG("File modified~n", []), modified + end end end. @@ -285,6 +293,9 @@ strip_date([C | Rest]) -> send_return_value({412,_,_}, _FileInfo)-> {status,{412,none,"Precondition Failed"}}; +send_return_value({400,_, {bad_date, BadDate}}, _FileInfo)-> + {status, {400, none, "Bad date: " ++ BadDate}}; + send_return_value({304,Info,Path}, FileInfo)-> Suffix = httpd_util:suffix(Path), MimeType = httpd_util:lookup_mime_default(Info#mod.config_db,Suffix, diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 20e22917e2..63ab0a5bae 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -30,6 +30,7 @@ include ../../vsn.mk VSN = $(INETS_VSN) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -41,8 +42,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # ---------------------------------------------------- MODULES = \ - inets_service \ inets \ + inets_service \ inets_app \ inets_sup \ inets_regexp diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index e6d315819c..779dd8e439 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,6 +18,11 @@ {"%VSN%", [ + {"5.7.2", + [ + {restart_application, inets} + ] + }, {"5.7.1", [ {restart_application, inets} @@ -35,6 +40,11 @@ } ], [ + {"5.7.2", + [ + {restart_application, inets} + ] + }, {"5.7.1", [ {restart_application, inets} diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk index b6e9fe1d96..35fb0d7eca 100644 --- a/lib/inets/src/inets_app/inets.mk +++ b/lib/inets/src/inets_app/inets.mk @@ -33,6 +33,10 @@ ifeq ($(WARN_UNUSED_WARS), true) ERL_COMPILE_FLAGS += +warn_unused_vars endif +ifeq ($(shell erl -noshell -eval 'io:format("~4s", [erlang:system_info(otp_release)])' -s init stop), R14B) +INETS_ERL_COMPILE_FLAGS += -D'OTP-R14B-COMPILER' +endif + INETS_APP_VSN_COMPILE_FLAGS = \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl index f89dac195c..a057a51e2c 100644 --- a/lib/inets/src/inets_app/inets_service.erl +++ b/lib/inets/src/inets_app/inets_service.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,6 +20,21 @@ -module(inets_service). +-ifdef('OTP-R14B-COMPILER'). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{start_standalone, 1}, + {start_service, 1}, + {stop_service, 1}, + {services, 0}, + {service_info, 1}]; +behaviour_info(_) -> + undefined. + +-else. + %% Starts service stand-alone %% start_standalone(Config) -> % {ok, Pid} | {error, Reason} %% <service>:start_link(Config). @@ -67,3 +82,5 @@ -callback service_info(Service :: term()) -> {ok, [{Property :: term(), Value :: term()}]} | {error, Reason :: term()}. + +-endif. diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl index b33c0a98f4..8d8fce388d 100644 --- a/lib/inets/src/tftp/tftp.erl +++ b/lib/inets/src/tftp/tftp.erl @@ -224,6 +224,20 @@ service_info/1 ]). +-ifdef('OTP-R14B-COMPILER'). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{prepare, 6}, + {open, 6}, + {read, 1}, + {write, 2}, + {abort, 3}]; +behaviour_info(_) -> + undefined. + +-else. -type peer() :: {PeerType :: inet | inet6, PeerHost :: inet:ip_address(), @@ -266,6 +280,8 @@ -callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'. +-endif. + -include("tftp.hrl"). diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index 3ebd02229e..ffb58c91b6 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -196,7 +196,9 @@ test_filenames() -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_testcase(Case, Config) - when (Case =:= open) orelse (Case =:= open_port) -> + when (Case =:= open) orelse + (Case =:= open_port) -> + put(ftp_testcase, Case), io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]), inets:start(), NewConfig = data_dir(Config), @@ -266,7 +268,7 @@ do_init_per_testcase(Case, Config) -> end, Opts2 = case string:tokens(atom_to_list(Case), [$_]) of - [_, "active" | _] -> + ["active" | _] -> [{mode, active} | Opts1]; _ -> [{mode, passive} | Opts1] @@ -367,8 +369,11 @@ open(Config) when is_list(Config) -> tc_open(Host) -> + p("tc_open -> entry with" + "~n Host: ~p", [Host]), {ok, Pid} = ?ftp_open(Host, []), ok = ftp:close(Pid), + p("tc_open -> try (ok) open 1"), {ok, Pid1} = ftp:open({option_list, [{host,Host}, {port, ?FTP_PORT}, @@ -376,11 +381,13 @@ tc_open(Host) -> {timeout, 30000}]}), ok = ftp:close(Pid1), + p("tc_open -> try (fail) open 2"), {error, ehost} = ftp:open({option_list, [{port, ?FTP_PORT}, {flags, [verbose]}]}), {ok, Pid2} = ftp:open(Host), ok = ftp:close(Pid2), + p("tc_open -> try (ok) open 3"), {ok, NewHost} = inet:getaddr(Host, inet), {ok, Pid3} = ftp:open(NewHost), ftp:user(Pid3, ?FTP_USER, ?FTP_PASS), @@ -392,33 +399,68 @@ tc_open(Host) -> %% Bad input that has default values are ignored and the defult %% is used. + p("tc_open -> try (ok) open 4"), {ok, Pid4} = - ftp:open({option_list, [{host, Host}, {port, badarg}, - {flags, [verbose]}, + ftp:open({option_list, [{host, Host}, + {port, badarg}, + {flags, [verbose]}, {timeout, 30000}]}), test_server:sleep(100), ok = ftp:close(Pid4), + + p("tc_open -> try (ok) open 5"), {ok, Pid5} = - ftp:open({option_list, [{host, Host}, {port, ?FTP_PORT}, - {flags, [verbose]}, + ftp:open({option_list, [{host, Host}, + {port, ?FTP_PORT}, + {flags, [verbose]}, {timeout, -42}]}), test_server:sleep(100), ok = ftp:close(Pid5), + + p("tc_open -> try (ok) open 6"), {ok, Pid6} = - ftp:open({option_list, [{host, Host}, {port, ?FTP_PORT}, + ftp:open({option_list, [{host, Host}, + {port, ?FTP_PORT}, {flags, [verbose]}, - {mode, cool}]}), + {mode, cool}]}), test_server:sleep(100), ok = ftp:close(Pid6), + p("tc_open -> try (ok) open 7"), {ok, Pid7} = ftp:open(Host, [{port, ?FTP_PORT}, {verbose, true}, {timeout, 30000}]), ok = ftp:close(Pid7), + p("tc_open -> try (ok) open 8"), {ok, Pid8} = ftp:open(Host, ?FTP_PORT), ok = ftp:close(Pid8), + p("tc_open -> try (ok) open 9"), + {ok, Pid9} = + ftp:open(Host, [{port, ?FTP_PORT}, + {verbose, true}, + {timeout, 30000}, + {dtimeout, -99}]), + ok = ftp:close(Pid9), + + p("tc_open -> try (ok) open 10"), + {ok, Pid10} = + ftp:open(Host, [{port, ?FTP_PORT}, + {verbose, true}, + {timeout, 30000}, + {dtimeout, "foobar"}]), + ok = ftp:close(Pid10), + + p("tc_open -> try (ok) open 11"), + {ok, Pid11} = + ftp:open(Host, [{port, ?FTP_PORT}, + {verbose, true}, + {timeout, 30000}, + {dtimeout, 1}]), + ok = ftp:close(Pid11), + + p("tc_open -> done"), ok. @@ -445,7 +487,7 @@ passive_user(suite) -> []; passive_user(Config) when is_list(Config) -> Pid = ?config(ftp, Config), - io:format("Pid: ~p~n",[Pid]), + p("Pid: ~p",[Pid]), do_user(Pid). @@ -967,13 +1009,13 @@ api_missuse(doc)-> ["Test that behaviour of the ftp process if the api is abused"]; api_missuse(suite) -> []; api_missuse(Config) when is_list(Config) -> - io:format("api_missuse -> entry~n", []), + p("api_missuse -> entry"), Flag = process_flag(trap_exit, true), Pid = ?config(ftp, Config), Host = ftp_host(Config), %% Serious programming fault, connetion will be shut down - io:format("api_missuse -> verify bad call termination (~p)~n", [Pid]), + p("api_missuse -> verify bad call termination (~p)", [Pid]), case (catch gen_server:call(Pid, {self(), foobar, 10}, infinity)) of {error, {connection_terminated, 'API_violation'}} -> ok; @@ -983,23 +1025,23 @@ api_missuse(Config) when is_list(Config) -> test_server:sleep(500), undefined = process_info(Pid, status), - io:format("api_missuse -> start new client~n", []), + p("api_missuse -> start new client"), {ok, Pid2} = ?ftp_open(Host, []), %% Serious programming fault, connetion will be shut down - io:format("api_missuse -> verify bad cast termination~n", []), + p("api_missuse -> verify bad cast termination"), gen_server:cast(Pid2, {self(), foobar, 10}), test_server:sleep(500), undefined = process_info(Pid2, status), - io:format("api_missuse -> start new client~n", []), + p("api_missuse -> start new client"), {ok, Pid3} = ?ftp_open(Host, []), %% Could be an innocent misstake the connection lives. - io:format("api_missuse -> verify bad bang~n", []), + p("api_missuse -> verify bad bang"), Pid3 ! foobar, test_server:sleep(500), {status, _} = process_info(Pid3, status), process_flag(trap_exit, Flag), - io:format("api_missuse -> done~n", []), + p("api_missuse -> done"), ok. @@ -1567,9 +1609,9 @@ split([], I, Is) -> lists:reverse([lists:reverse(I)| Is]). do_ftp_open(Host, Opts) -> - io:format("do_ftp_open -> entry with" - "~n Host: ~p" - "~n Opts: ~p", [Host, Opts]), + p("do_ftp_open -> entry with" + "~n Host: ~p" + "~n Opts: ~p", [Host, Opts]), case ftp:open(Host, Opts) of {ok, _} = OK -> OK; @@ -1595,7 +1637,7 @@ passwd() -> ftpd_hosts(Config) -> DataDir = ?config(data_dir, Config), FileName = filename:join([DataDir, "../ftp_SUITE_data/", ftpd_hosts]), - io:format("FileName: ~p~n", [FileName]), + p("FileName: ~p", [FileName]), case file:consult(FileName) of {ok, [Hosts]} when is_list(Hosts) -> Hosts; diff --git a/lib/inets/test/ftp_windows_2003_server_test.erl b/lib/inets/test/ftp_windows_2003_server_test.erl index 57f1ae8358..32f25713f8 100644 --- a/lib/inets/test/ftp_windows_2003_server_test.erl +++ b/lib/inets/test/ftp_windows_2003_server_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -87,14 +87,22 @@ end_per_testcase(Case, Config) -> %% Description: Returns a list of all test cases in this test suite %%-------------------------------------------------------------------- all() -> - [open, open_port, {group, passive}, {group, active}, - api_missuse, not_owner, {group, progress_report}]. + [ + open, + open_port, + {group, passive}, + {group, active}, + api_missuse, + not_owner, + {group, progress_report} + ]. groups() -> - [{passive, [], ftp_suite_lib:passive(suite)}, - {active, [], ftp_suite_lib:active(suite)}, - {progress_report, [], - ftp_suite_lib:progress_report(suite)}]. + [ + {passive, [], ftp_suite_lib:passive(suite)}, + {active, [], ftp_suite_lib:active(suite)}, + {progress_report, [], ftp_suite_lib:progress_report(suite)} + ]. init_per_group(_GroupName, Config) -> Config. diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index f95fb93669..d86e52f3d5 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -250,10 +250,10 @@ init_per_testcase(Case, Config) -> init_per_testcase(Case, 2, Config). init_per_testcase(Case, Timeout, Config) -> - io:format(user, "~n~n*** INIT ~w:~w[~w] ***~n~n", - [?MODULE, Case, Timeout]), - PrivDir = ?config(priv_dir, Config), - tsp("init_per_testcase -> stop inets"), + io:format(user, + "~n~n*** INIT ~w:~w[~w] ***" + "~n~n", [?MODULE, Case, Timeout]), + PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), TmpConfig = lists:keydelete(watchdog, 1, Config), @@ -289,12 +289,12 @@ init_per_testcase(Case, Timeout, Config) -> throw:{error, {failed_starting, App, _}} -> SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; - _:X -> + skip(SkipString); + _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; _ -> @@ -323,14 +323,14 @@ init_per_testcase(Case, Timeout, Config) -> ], case lists:member(Rest, BadCases) of true -> - [{skip, "TC and server not compatible"}| + [skip("TC and server not compatible") | TmpConfig]; false -> inets:start(), [{watchdog, Dog} | TmpConfig] end; false -> - [{skip, "proxy not responding"} | TmpConfig] + [skip("proxy not responding") | TmpConfig] end end; @@ -360,20 +360,19 @@ init_per_testcase(Case, Timeout, Config) -> io_lib:format("Failed starting apps: ~p", [X])), {skip, SkipString} end; + _ -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), - Server = - %% Will start inets - inets_test_lib:start_http_server( - filename:join(PrivDir, IpConfFile)), + %% Will start inets + Server = start_http_server(PrivDir, IpConfFile), [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, %% This will fail for the ipv6_ - cases (but that is ok) - httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, - ["localhost", ?IPV6_LOCAL_HOST]}}, - {ipfamily, inet6fb4}]), - + ProxyExceptions = ["localhost", ?IPV6_LOCAL_HOST], + http:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + inets:enable_trace(max, io, httpc), + %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), NewConfig. @@ -390,7 +389,10 @@ init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) -> tsp("init_per_testcase(~w) -> Server: ~p", [Tag, Server]), [{local_ssl_server, Server} | Config2]. - +start_http_server(ConfDir, ConfFile) -> + inets_test_lib:start_http_server( filename:join(ConfDir, ConfFile) ). + + %%-------------------------------------------------------------------- %% Function: end_per_testcase(Case, Config) -> _ %% Case - atom() @@ -726,7 +728,7 @@ test_pipeline(URL) -> p("test_pipeline -> received reply for (async) request 2"), ok; {http, Msg1} -> - test_server:fail(Msg1) + tsf(Msg1) end; {http, {RequestId2, {{_, 200, _}, _, _}}} -> io:format("test_pipeline -> received reply for (async) request 2 - now wait for 1"), @@ -735,14 +737,14 @@ test_pipeline(URL) -> io:format("test_pipeline -> received reply for (async) request 1"), ok; {http, Msg2} -> - test_server:fail(Msg2) + tsf(Msg2) end; {http, Msg3} -> - test_server:fail(Msg3) + tsf(Msg3) after 60000 -> receive Any1 -> tsp("received crap after timeout: ~n ~p", [Any1]), - test_server:fail({error, {timeout, Any1}}) + tsf({error, {timeout, Any1}}) end end, @@ -767,7 +769,7 @@ test_pipeline(URL) -> p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"), receive {http, {RequestId3, _}} -> - test_server:fail(http_cancel_request_failed) + tsf(http_cancel_request_failed) after 3000 -> ok end, @@ -780,11 +782,11 @@ test_pipeline(URL) -> tsp("Receive : ~p", [Res]), BinBody4; {http, Msg4} -> - test_server:fail(Msg4) + tsf(Msg4) after 60000 -> receive Any2 -> tsp("received crap after timeout: ~n ~p", [Any2]), - test_server:fail({error, {timeout, Any2}}) + tsf({error, {timeout, Any2}}) end end, @@ -794,7 +796,7 @@ test_pipeline(URL) -> p("test_pipeline -> ensure no unexpected incomming"), receive {http, Any} -> - test_server:fail({unexpected_message, Any}) + tsf({unexpected_message, Any}) after 500 -> ok end, @@ -816,11 +818,11 @@ http_trace(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], "TRACE /dummy.html" ++ _}} -> ok; {ok, {{_,200,_}, [_ | _], WrongBody}} -> - test_server:fail({wrong_body, WrongBody}); + tsf({wrong_body, WrongBody}); {ok, WrongReply} -> - test_server:fail({wrong_reply, WrongReply}); + tsf({wrong_reply, WrongReply}); Error -> - test_server:fail({failed, Error}) + tsf({failed, Error}) end; _ -> {skip, "Failed to start local http-server"} @@ -843,7 +845,7 @@ http_async(Config) when is_list(Config) -> {http, {RequestId, {{_, 200, _}, _, BinBody}}} -> BinBody; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, inets_test_lib:check_body(binary_to_list(Body)), @@ -853,7 +855,7 @@ http_async(Config) when is_list(Config) -> ok = httpc:cancel_request(NewRequestId), receive {http, {NewRequestId, _NewResult}} -> - test_server:fail(http_cancel_request_failed) + tsf(http_cancel_request_failed) after 3000 -> ok end; @@ -902,7 +904,7 @@ http_save_to_file_async(Config) when is_list(Config) -> {http, {RequestId, saved_to_file}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, {ok, Bin} = file:read_file(FilePath), @@ -1448,10 +1450,10 @@ proxy_options(Config) when is_list(Config) -> {value, {"allow", _}} -> ok; _ -> - test_server:fail(http_options_request_failed) + tsf(http_options_request_failed) end; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1472,7 +1474,7 @@ proxy_head(Config) when is_list(Config) -> {ok, {{_,200, _}, [_ | _], []}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1491,7 +1493,7 @@ proxy_get(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} -> inets_test_lib:check_body(Body); Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1570,7 +1572,7 @@ proxy_post(Config) when is_list(Config) -> {ok, {{_,405,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1595,7 +1597,7 @@ proxy_put(Config) when is_list(Config) -> {ok, {{_,405,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1620,7 +1622,7 @@ proxy_delete(Config) when is_list(Config) -> {ok, {{_,404,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1676,7 +1678,7 @@ proxy_auth(Config) when is_list(Config) -> {ok, {{_,200, _}, [_ | _], [_|_]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1762,7 +1764,7 @@ http_stream(Config) when is_list(Config) -> {http, {RequestId, stream_start, _Headers}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, StreamedBody = receive_streamed_body(RequestId, <<>>), @@ -1817,7 +1819,7 @@ once(URL) -> [RequestId, Pid]), Pid; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, tsp("once -> request handler: ~p", [NewPid]), @@ -1860,7 +1862,7 @@ proxy_stream(Config) when is_list(Config) -> {http, {RequestId, stream_start, _Headers}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, StreamedBody = receive_streamed_body(RequestId, <<>>), @@ -1878,22 +1880,31 @@ parse_url(suite) -> []; parse_url(Config) when is_list(Config) -> %% ipv6 - {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]} - = http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html"), + {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} = + http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html"), + {ok, {http,[],"[2010:836B:4179::836B:4179]",80,"/foobar.html",[]}} = + http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html", + [{ipv6_host_with_brackets, true}]), + {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} = + http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html", + [{ipv6_host_with_brackets, false}]), + {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} = + http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html", + [{foo, false}]), {error, {malformed_url,"http://2010:836B:4179::836B:4179/foobar.html"}} = http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"), %% ipv4 - {http,[],"127.0.0.1",80,"/foobar.html",[]} = + {ok, {http,[],"127.0.0.1",80,"/foobar.html",[]}} = http_uri:parse("http://127.0.0.1/foobar.html"), %% host - {http,[],"localhost",8888,"/foobar.html",[]} = + {ok, {http,[],"localhost",8888,"/foobar.html",[]}} = http_uri:parse("http://localhost:8888/foobar.html"), %% Userinfo - {http,"nisse:foobar","localhost",8888,"/foobar.html",[]} = + {ok, {http,"nisse:foobar","localhost",8888,"/foobar.html",[]}} = http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"), %% Scheme error @@ -1902,18 +1913,20 @@ parse_url(Config) when is_list(Config) -> http_uri:parse("localhost:8888/foobar.html"), %% Query - {http,[],"localhost",8888,"/foobar.html","?foo=bar&foobar=42"} = + {ok, {http,[],"localhost",8888,"/foobar.html","?foo=bar&foobar=42"}} = http_uri:parse("http://localhost:8888/foobar.html?foo=bar&foobar=42"), %% Esc chars - {http,[],"www.somedomain.com",80,"/%2Eabc",[]} = + {ok, {http,[],"www.somedomain.com",80,"/%2Eabc",[]}} = http_uri:parse("http://www.somedomain.com/%2Eabc"), - {http,[],"www.somedomain.com",80,"/%252Eabc",[]} = + {ok, {http,[],"www.somedomain.com",80,"/%252Eabc",[]}} = http_uri:parse("http://www.somedomain.com/%252Eabc"), - {http,[],"www.somedomain.com",80,"/%25abc",[]} = + {ok, {http,[],"www.somedomain.com",80,"/%25abc",[]}} = http_uri:parse("http://www.somedomain.com/%25abc"), - {http,[],"www.somedomain.com",80,"/%25abc", "?foo=bar"} = + {ok, {http,[],"www.somedomain.com",80,"/%25abc", "?foo=bar"}} = http_uri:parse("http://www.somedomain.com/%25abc?foo=bar"), + + ok. @@ -2058,12 +2071,14 @@ http_invalid_http(Config) when is_list(Config) -> %%------------------------------------------------------------------------- +-define(GOOGLE, "www.google.com"). + hexed_query_otp_6191(doc) -> []; hexed_query_otp_6191(suite) -> []; hexed_query_otp_6191(Config) when is_list(Config) -> - Google = "www.google.com", + Google = ?GOOGLE, GoogleSearch = "http://" ++ Google ++ "/search", Search1 = "?hl=en&q=a%D1%85%D1%83%D0%B9&btnG=Google+Search", URI1 = GoogleSearch ++ Search1, @@ -2072,11 +2087,32 @@ hexed_query_otp_6191(Config) when is_list(Config) -> Search3 = "?hl=en&q=%foo", URI3 = GoogleSearch ++ Search3, - {http, [], Google, 80, "/search", _} = http_uri:parse(URI1), - {http, [], Google, 80, "/search", _} = http_uri:parse(URI2), - {http, [], Google, 80, "/search", _} = http_uri:parse(URI3), + Verify1 = + fun({http, [], ?GOOGLE, 80, "/search", _}) -> ok; + (_) -> error + end, + Verify2 = Verify1, + Verify3 = Verify1, + verify_uri(URI1, Verify1), + verify_uri(URI2, Verify2), + verify_uri(URI3, Verify3), ok. +verify_uri(URI, Verify) -> + case http_uri:parse(URI) of + {ok, ParsedURI} -> + case Verify(ParsedURI) of + ok -> + ok; + error -> + Reason = {unexpected_parse_result, URI, ParsedURI}, + ERROR = {error, Reason}, + throw(ERROR) + end; + {error, _} = ERROR -> + throw(ERROR) + end. + %%------------------------------------------------------------------------- @@ -2945,7 +2981,7 @@ receive_streamed_body(RequestId, Body) -> {http, {RequestId, stream_end, _Headers}} -> Body; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end. receive_streamed_body(RequestId, Body, Pid) -> @@ -2959,7 +2995,7 @@ receive_streamed_body(RequestId, Body, Pid) -> {http, {RequestId, stream_end, _Headers}} -> Body; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end. %% Perform a synchronous stop @@ -3417,7 +3453,7 @@ handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) -> end. check_cookie([]) -> - test_server:fail(no_cookie_header); + tsf(no_cookie_header); check_cookie(["cookie:" ++ _Value | _]) -> ok; check_cookie([_Head | Tail]) -> @@ -3475,9 +3511,9 @@ p(F, A) -> io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). tsp(F) -> - tsp(F, []). + inets_test_lib:tsp(F). tsp(F, A) -> - test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + inets_test_lib:tsp(F, A). tsf(Reason) -> test_server:fail(Reason). @@ -3532,3 +3568,6 @@ ensure_started(App) when is_atom(App) -> throw({error, {failed_starting, App, Error}}) end. + +skip(Reason) -> + {skip, Reason}. diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index 2a6110e3ea..07d94ea97a 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,7 +19,6 @@ %% -module(httpd_1_1). --author('[email protected]'). -include("test_server.hrl"). -include("test_server_line.hrl"). @@ -159,70 +158,79 @@ if_test(Type, Port, Host, Node, DocRoot)-> calendar:datetime_to_gregorian_seconds(FileInfo#file_info.mtime), Mod = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec-1)), - + CreatedSec-1)), + %% Test that we get the data when the file is modified ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ Host ++ - "\r\nIf-Modified-Since:" ++ - Mod ++ "\r\n\r\n", - [{statuscode, 200}]), - Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec+100)), - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++"\r\nIf-Modified-Since:" - ++ Mod1 ++"\r\n\r\n", - [{statuscode, 304}]), + "GET / HTTP/1.1\r\nHost:" ++ Host ++ + "\r\nIf-Modified-Since:" ++ + Mod ++ "\r\n\r\n", + [{statuscode, 200}]), + Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( + CreatedSec+100)), + ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + "GET / HTTP/1.1\r\nHost:" + ++ Host ++"\r\nIf-Modified-Since:" + ++ Mod1 ++"\r\n\r\n", + [{statuscode, 304}]), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + "GET / HTTP/1.1\r\nHost:" ++ Host ++ + "\r\nIf-Modified-Since:" ++ + "AAA[...]AAAA" ++ "\r\n\r\n", + [{statuscode, 400}]), + + Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec+1)), + CreatedSec+1)), %% Control that the If-Unmodified-Header lmits the response ok = httpd_test_lib:verify_request(Type,Host,Port,Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:" ++ Mod2 - ++ "\r\n\r\n", - [{statuscode, 200}]), + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:" ++ Mod2 + ++ "\r\n\r\n", + [{statuscode, 200}]), Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec-1)), + CreatedSec-1)), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:"++ Mod3 - ++"\r\n\r\n", - [{statuscode, 412}]), - + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:"++ Mod3 + ++"\r\n\r\n", + [{statuscode, 412}]), + %% Control that we get the body when the etag match ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ Host - ++"\r\n"++ - "If-Match:"++ - httpd_util:create_etag(FileInfo)++ - "\r\n\r\n", - [{statuscode, 200}]), + "GET / HTTP/1.1\r\nHost:" ++ Host + ++"\r\n"++ + "If-Match:"++ + httpd_util:create_etag(FileInfo)++ + "\r\n\r\n", + [{statuscode, 200}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ - Host ++ "\r\n"++ - "If-Match:NotEtag\r\n\r\n", - [{statuscode, 412}]), + "GET / HTTP/1.1\r\nHost:" ++ + Host ++ "\r\n"++ + "If-Match:NotEtag\r\n\r\n", + [{statuscode, 412}]), %% Control the response when the if-none-match header is there ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++"\r\n"++ - "If-None-Match:NoTaag," ++ - httpd_util:create_etag(FileInfo) ++ - "\r\n\r\n", - [{statuscode, 304}]), - + "GET / HTTP/1.1\r\nHost:" + ++ Host ++"\r\n"++ + "If-None-Match:NoTaag," ++ + httpd_util:create_etag(FileInfo) ++ + "\r\n\r\n", + [{statuscode, 304}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ "\r\n"++ - "If-None-Match:NotEtag," - "NeihterEtag\r\n\r\n", - [{statuscode,200}]). + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ "\r\n"++ + "If-None-Match:NotEtag," + "NeihterEtag\r\n\r\n", + [{statuscode,200}]), + ok. http_trace(Type, Port, Host, Node)-> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index faeed3b5f9..ba31788ccc 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -686,6 +686,19 @@ end_per_testcase2(Case, Config) -> %%------------------------------------------------------------------------- +http_1_1_ip(doc) -> + ["HTTP/1.1"]; +http_1_1_ip(suite) -> + [ + ip_host, + ip_chunked, + ip_expect, + ip_range, + ip_if_test, + ip_http_trace, + ip_http1_1_head, + ip_mod_cgi_chunked_encoding_test + ]. %%------------------------------------------------------------------------- @@ -2276,24 +2289,24 @@ ticket_5913(doc) -> ["Tests that a header without last-modified is handled"]; ticket_5913(suite) -> []; ticket_5913(Config) -> - ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config), - ?IP_PORT, ?config(node, Config), + ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config), + ?IP_PORT, ?config(node, Config), "GET /cgi-bin/erl/httpd_example:get_bin " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, - {version, "HTTP/1.0"}]), + {version, "HTTP/1.0"}]), ok. ticket_6003(doc) -> ["Tests that a URI with a bad hexadecimal code is handled"]; ticket_6003(suite) -> []; ticket_6003(Config) -> - ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config), - ?IP_PORT, ?config(node, Config), - "GET http://www.erlang.org/%skalle " - "HTTP/1.0\r\n\r\n", - [{statuscode, 400}, - {version, "HTTP/1.0"}]), + ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config), + ?IP_PORT, ?config(node, Config), + "GET http://www.erlang.org/%skalle " + "HTTP/1.0\r\n\r\n", + [{statuscode, 400}, + {version, "HTTP/1.0"}]), ok. ticket_7304(doc) -> diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index f23d0b4765..4cd38f2ec4 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -59,9 +59,28 @@ init_per_suite(Config) -> "~n Config: ~p", [Config]), ok = inets:start(), PrivDir = ?config(priv_dir, Config), - HttpdConf = [{port, 0}, {ipfamily, inet}, - {server_name, "httpd_test"}, {server_root, PrivDir}, - {document_root, PrivDir}, {bind_address, "localhost"}], + + Dummy = +"<HTML> +<HEAD> +<TITLE>/index.html</TITLE> +</HEAD> +<BODY> +DUMMY +</BODY> +</HTML>", + + DummyFile = filename:join([PrivDir,"dummy.html"]), + {ok, Fd} = file:open(DummyFile, [write]), + ok = file:write(Fd, Dummy), + ok = file:close(Fd), + HttpdConf = [{port, 0}, + {ipfamily, inet}, + {server_name, "httpd_test"}, + {server_root, PrivDir}, + {document_root, PrivDir}, + {bind_address, "localhost"}], + [{httpd_conf, HttpdConf} | Config]. %%-------------------------------------------------------------------- @@ -133,6 +152,10 @@ uri_too_long_414(Config) when is_list(Config) -> {version, "HTTP/0.9"}]), inets:stop(httpd, Pid). + +%%------------------------------------------------------------------------- +%%------------------------------------------------------------------------- + header_too_long_413(doc) -> ["Test that too long headers's get 413 HTTP code"]; header_too_long_413(suite) -> @@ -152,34 +175,92 @@ header_too_long_413(Config) when is_list(Config) -> {version, "HTTP/1.1"}]), inets:stop(httpd, Pid). + +%%------------------------------------------------------------------------- +%%------------------------------------------------------------------------- + escaped_url_in_error_body(doc) -> ["Test Url-encoding see OTP-8940"]; escaped_url_in_error_body(suite) -> []; escaped_url_in_error_body(Config) when is_list(Config) -> - tsp("escaped_url_in_error_body -> entry with" - "~n Config: ~p", [Config]), - HttpdConf = ?config(httpd_conf, Config), - {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), - Info = httpd:info(Pid), - Port = proplists:get_value(port, Info), - _Address = proplists:get_value(bind_address, Info), - Path = "/<b>this_is_bold</b>", - URL = ?URL_START ++ integer_to_list(Port) ++ Path, - EscapedPath = http_uri:encode(Path), - {ok, {404, Body1}} = httpc:request(get, {URL, []}, - [{url_encode, true}, - {version, "HTTP/1.0"}], - [{full_result, false}]), - EscapedPath = find_URL_path(string:tokens(Body1, " ")), - {ok, {404, Body2}} = httpc:request(get, {URL, []}, - [{url_encode, false}, - {version, "HTTP/1.0"}], - [{full_result, false}]), + tsp("escaped_url_in_error_body -> entry"), + HttpdConf = ?config(httpd_conf, Config), + {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), + Info = httpd:info(Pid), + Port = proplists:get_value(port, Info), + _Address = proplists:get_value(bind_address, Info), + + %% Request 1 + tsp("escaped_url_in_error_body -> request 1"), + URL1 = ?URL_START ++ integer_to_list(Port), + %% Make sure the server is ok, by making a request for a valid page + case httpc:request(get, {URL1 ++ "/dummy.html", []}, + [{url_encode, false}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {200, _}} -> + %% Don't care about the the body, just that we get a ok response + ok; + {ok, UnexpectedOK1} -> + tsf({unexpected_ok_1, UnexpectedOK1}) + end, + + %% Request 2 + tsp("escaped_url_in_error_body -> request 2"), + %% Make sure the server is ok, by making a request for a valid page + case httpc:request(get, {URL1 ++ "/dummy.html", []}, + [{url_encode, true}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {200, _}} -> + %% Don't care about the the body, just that we get a ok response + ok; + {ok, UnexpectedOK2} -> + tsf({unexpected_ok_2, UnexpectedOK2}) + end, + + %% Request 3 + tsp("escaped_url_in_error_body -> request 3"), + %% Ask for a non-existing page(1) + Path = "/<b>this_is_bold<b>", HTMLEncodedPath = http_util:html_encode(Path), - HTMLEncodedPath = find_URL_path(string:tokens(Body2, " ")), + URL2 = URL1 ++ Path, + case httpc:request(get, {URL2, []}, + [{url_encode, true}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {404, Body3}} -> + case find_URL_path(string:tokens(Body3, " ")) of + HTMLEncodedPath -> + ok; + BadPath3 -> + tsf({unexpected_path_3, HTMLEncodedPath, BadPath3}) + end; + {ok, UnexpectedOK3} -> + tsf({unexpected_ok_1, UnexpectedOK3}) + end, + + %% Request 4 + tsp("escaped_url_in_error_body -> request 4"), + %% Ask for a non-existing page(2) + case httpc:request(get, {URL2, []}, + [{url_encode, false}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {404, Body4}} -> + case find_URL_path(string:tokens(Body4, " ")) of + HTMLEncodedPath -> + ok; + BadPath4 -> + tsf({unexpected_path_2, HTMLEncodedPath, BadPath4}) + end; + {ok, UnexpectedOK4} -> + tsf({unexpected_ok_4, UnexpectedOK4}) + end, + tsp("escaped_url_in_error_body -> stop inets"), inets:stop(httpd, Pid), - tsp("escaped_url_in_error_body -> done"), + tsp("escaped_url_in_error_body -> done"), ok. find_URL_path([]) -> @@ -191,7 +272,14 @@ find_URL_path([_ | Rest]) -> tsp(F) -> - tsp(F, []). + inets_test_lib:tsp(F). tsp(F, A) -> - test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + inets_test_lib:tsp(F, A). + +tsf(Reason) -> + test_server:fail(Reason). + + +skip(Reason) -> + {skip, Reason}. diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 1754cec7bc..5016cdb9e6 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the @@ -88,13 +88,13 @@ actions(Type, Port, Host, Node) -> %%------------------------------------------------------------------------- security(ServerRoot, Type, Port, Host, Node) -> -%% io:format(user, "~w:security -> entry with" -%% "~n ServerRoot: ~p" -%% "~n Type: ~p" -%% "~n Port: ~p" -%% "~n Host: ~p" -%% "~n Node: ~p" -%% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), + %% io:format(user, "~w:security -> entry with" + %% "~n ServerRoot: ~p" + %% "~n Type: ~p" + %% "~n Port: ~p" + %% "~n Host: ~p" + %% "~n Node: ~p" + %% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), %% io:format(user, "~w:security -> register~n", [?MODULE]), global:register_name(mod_security_test, self()), % Receive events @@ -175,8 +175,8 @@ security(ServerRoot, Type, Port, Host, Node) -> [{"one",_, Port, OpenDir,_}] -> ok; Blocked -> - io:format(user, "~w:security -> Blocked: ~p" - "~n", [?MODULE, Blocked]), + %% io:format(user, "~w:security -> Blocked: ~p" + %% "~n", [?MODULE, Blocked]), exit({unexpected_blocked, Blocked}) end, @@ -917,11 +917,11 @@ list_users(Node, Root, _Host, Port, Dir) -> receive_security_event(Event, Node, Port) -> -%% io:format(user, "~w:receive_security_event -> entry with" -%% "~n Event: ~p" -%% "~n Node: ~p" -%% "~n Port: ~p" -%% "~n", [?MODULE, Event, Node, Port]), + %% io:format(user, "~w:receive_security_event -> entry with" + %% "~n Event: ~p" + %% "~n Node: ~p" + %% "~n Port: ~p" + %% "~n", [?MODULE, Event, Node, Port]), receive Event -> ok; diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 581461fe03..1c7bb512cc 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2001-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the @@ -140,6 +140,9 @@ request(#state{mfa = {Module, Function, Args}, HeadRequest = lists:sublist(RequestStr, 1, 4), receive {tcp, Socket, Data} -> + io:format("~p ~w[~w]request -> received (tcp) data" + "~n Data: ~p" + "~n", [self(), ?MODULE, ?LINE, Data]), print(tcp, Data, State), case Module:Function([Data | Args]) of {ok, Parsed} -> @@ -150,11 +153,19 @@ request(#state{mfa = {Module, Function, Args}, request(State#state{mfa = NewMFA}, TimeOut) end; {tcp_closed, Socket} when Function =:= whole_body -> + io:format("~p ~w[~w]request -> " + "received (tcp) closed when whole_body" + "~n", [self(), ?MODULE, ?LINE]), print(tcp, "closed", State), State#state{body = hd(Args)}; {tcp_closed, Socket} -> + io:format("~p ~w[~w]request -> received (tcp) closed" + "~n", [self(), ?MODULE, ?LINE]), test_server:fail(connection_closed); {tcp_error, Socket, Reason} -> + io:format("~p ~w[~w]request -> received (tcp) error" + "~n Reason: ~p" + "~n", [self(), ?MODULE, ?LINE, Reason]), test_server:fail({tcp_error, Reason}); {ssl, Socket, Data} -> print(ssl, Data, State), @@ -174,11 +185,21 @@ request(#state{mfa = {Module, Function, Args}, {ssl_error, Socket, Reason} -> test_server:fail({ssl_error, Reason}) after TimeOut -> + io:format("~p ~w[~w]request -> timeout" + "~n", [self(), ?MODULE, ?LINE]), test_server:fail(connection_timed_out) end. handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body}, State = #state{request = RequestStr}) -> + io:format("~p ~w[~w]handle_http_msg -> entry with" + "~n Version: ~p" + "~n StatusCode: ~p" + "~n ReasonPharse: ~p" + "~n Headers: ~p" + "~n Body: ~p" + "~n", [self(), ?MODULE, ?LINE, + Version, StatusCode, ReasonPharse, Headers, Body]), case is_expect(RequestStr) of true -> State#state{status_line = {Version, @@ -235,13 +256,14 @@ handle_http_body(Body, State = #state{headers = Headers, end. validate(RequestStr, #state{status_line = {Version, StatusCode, _}, - headers = Headers, - body = Body}, Options, N, P) -> + headers = Headers, + body = Body}, Options, N, P) -> %% tsp("validate -> entry with" %% "~n StatusCode: ~p" %% "~n Headers: ~p" %% "~n Body: ~p", [StatusCode, Headers, Body]), + check_version(Version, Options), case lists:keysearch(statuscode, 1, Options) of {value, _} -> @@ -255,6 +277,7 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, list_to_integer(Headers#http_response_h.'content-length'), Body). + %%-------------------------------------------------------------------- %% Internal functions %%------------------------------------------------------------------ @@ -263,21 +286,20 @@ check_version(Version, Options) -> {value, {version, Version}} -> ok; {value, {version, Ver}} -> - test_server:fail({wrong_version, [{got, Version}, - {expected, Ver}]}); + tsf({wrong_version, [{got, Version}, + {expected, Ver}]}); _ -> case Version of "HTTP/1.1" -> ok; _ -> - test_server:fail({wrong_version, [{got, Version}, - {expected, "HTTP/1.1"}]}) + tsf({wrong_version, [{got, Version}, + {expected, "HTTP/1.1"}]}) end end. check_status_code(StatusCode, [], Options) -> - test_server:fail({wrong_status_code, [{got, StatusCode}, - {expected, Options}]}); + tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}); check_status_code(StatusCode, Current = [_ | Rest], Options) -> case lists:keysearch(statuscode, 1, Current) of {value, {statuscode, StatusCode}} -> @@ -285,8 +307,7 @@ check_status_code(StatusCode, Current = [_ | Rest], Options) -> {value, {statuscode, _OtherStatus}} -> check_status_code(StatusCode, Rest, Options); false -> - test_server:fail({wrong_status_code, [{got, StatusCode}, - {expected, Options}]}) + tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}) end. do_validate(_, [], _, _) -> @@ -317,8 +338,7 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> Header}) end, do_validate(Header, Rest, N, P); -do_validate(Header,[{no_last_modified,HeaderField}|Rest],N,P) -> -% io:format("Header: ~p~nHeaderField: ~p~n",[Header,HeaderField]), +do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) -> case lists:keysearch(HeaderField,1,Header) of {value,_} -> test_server:fail({wrong_header_field_value, HeaderField, @@ -331,7 +351,6 @@ do_validate(Header, [_Unknown | Rest], N, P) -> do_validate(Header, Rest, N, P). is_expect(RequestStr) -> - case inets_regexp:match(RequestStr, "xpect:100-continue") of {match, _, _}-> true; @@ -340,15 +359,15 @@ is_expect(RequestStr) -> end. %% OTP-5775, content-length -check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when Length /= 274-> - test_server:fail(content_length_error); +check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when (Length =/= 274) -> + tsf(content_length_error); check_body("GET /cgi-bin/cgi_echo HTTP/1.0\r\n\r\n", 200, "text/plain", _, Body) -> case size(Body) of 100 -> ok; _ -> - test_server:fail(content_length_error) + tsf(content_length_error) end; check_body(RequestStr, 200, "text/html", _, Body) -> diff --git a/lib/inviso/doc/src/make.dep b/lib/inviso/doc/src/make.dep deleted file mode 100644 index 9459f74e6d..0000000000 --- a/lib/inviso/doc/src/make.dep +++ /dev/null @@ -1,27 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex inviso.tex inviso_as_lib.tex inviso_chapter.tex \ - inviso_lfm.tex inviso_lfm_tpfreader.tex inviso_rt.tex \ - inviso_rt_meta.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: inviso_users_guide_pic1.ps - diff --git a/lib/jinterface/doc/src/make.dep b/lib/jinterface/doc/src/make.dep deleted file mode 100644 index a1b3c322c6..0000000000 --- a/lib/jinterface/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex jinterface.tex jinterface_users_guide.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 688cd0f78f..418bfae4b8 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -45,7 +45,15 @@ SUSE Linux Enterprise Server 10 (x86_64) kernel 2.6.16.27-0.6-smp, with lksctp-tools-1.0.6, briefly on Solaris 10, and later on SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64) - kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7.</p> + kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7, + and later also on FreeBSD 8.2. + </p> + <p> + This module was written for one-to-many style sockets + (type <c>seqpacket</c>). With the addition of + <seealso marker="#peeloff/2">peeloff/2</seealso>, one-to-one style + sockets (type <c>stream</c>) were introduced. + </p> <p>Record definitions for the <c>gen_sctp</c> module can be found using:</p> <pre> -include_lib("kernel/include/inet_sctp.hrl"). </pre> <p>These record definitions use the "new" spelling 'adaptation', @@ -254,15 +262,19 @@ </desc> </func> <func> - <name name="listen" arity="2"/> + <name name="listen" arity="2" clause_i="1"/> + <name name="listen" arity="2" clause_i="2"/> <fsummary>Set up a socket to listen.</fsummary> <desc> <p>Sets up a socket to listen on the IP address and port number - it is bound to. <c><anno>IsServer</anno></c> must be <c>true</c> - or <c>false</c>. - In the contrast to TCP, in SCTP there is no listening queue length. - If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e. - it will become an SCTP server socket.</p> + it is bound to.</p> + <p>For type <c>seqpacket</c> sockets (the default) + <c><anno>IsServer</anno></c> must be <c>true</c> or <c>false</c>. + In the contrast to TCP, in SCTP there is no listening queue length. + If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e. + it will become an SCTP server socket.</p> + <p>For type <c>stream</c> sockets <anno>Backlog</anno> defines + the backlog queue length just like in TCP.</p> </desc> </func> <func> @@ -295,12 +307,40 @@ is used. In particular, the socket is opened in <seealso marker="#option-binary">binary</seealso> and <seealso marker="#option-active">passive</seealso> mode, + with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large <seealso marker="#option-sndbuf">kernel</seealso> and driver <seealso marker="#option-buffer">buffers.</seealso></p> </desc> </func> <func> + <name name="peeloff" arity="2"/> + <fsummary> + Peel off a type <c>stream</c> socket from a type <c>seqpacket</c> one + </fsummary> + <desc> + <p> + Branch off an existing association <anno>Assoc</anno> + in a socket <anno>Socket</anno> of type <c>seqpacket</c> + (one-to-may style) into + a new socket <anno>NewSocket</anno> of type <c>stream</c> + (one-to-one style). + </p> + <p> + The existing association argument <anno>Assoc</anno> + can be either a + <seealso marker="#record-sctp_assoc_change"> + #sctp_assoc_change{} + </seealso> + record as returned from e.g + <seealso marker="#recv-2">recv/*</seealso>, + <seealso marker="#connect-5">connect/*</seealso> or + from a listening socket in active mode. Or it can be just + the field <c>assoc_id</c> integer from such a record. + </p> + </desc> + </func> + <func> <name name="recv" arity="1"/> <name name="recv" arity="2"/> <fsummary>Receive a message from a socket</fsummary> diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index e2dbcbe63d..26d1e27822 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -42,7 +42,7 @@ system.</p> <p>An Erlang runtime system to be monitored by a heart program, should be started with the command line flag <c>-heart</c> (see - also <seealso marker="erts:erl">erl(1)</seealso>. The <c>heart</c> + also <seealso marker="erts:erl">erl(1)</seealso>). The <c>heart</c> process is then started automatically:</p> <pre> % <input>erl -heart ...</input></pre> diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index bf513b7815..0f71a4f0f2 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -4,7 +4,7 @@ <appref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -231,6 +231,15 @@ MaxT = TickTime + TickTime / 4</code> <p><em>Note:</em> Normally, a terminating node is detected immediately.</p> </item> + <tag><c>shutdown_timeout = integer() | infinity</c></tag> + <item> + <p>Specifies the time <c>application_controller</c> will wait + for an application to terminate during node shutdown. If the + timer expires, <c>application_controller</c> will brutally + kill <c>application_master</c> of the hanging + application. If this parameter is undefined, it defaults + to <c>infinity</c>.</p> + </item> <tag><c>sync_nodes_mandatory = [NodeName]</c></tag> <item> <p>Specifies which other nodes <em>must</em> be alive in order diff --git a/lib/kernel/doc/src/make.dep b/lib/kernel/doc/src/make.dep deleted file mode 100644 index f79d1c6367..0000000000 --- a/lib/kernel/doc/src/make.dep +++ /dev/null @@ -1,28 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: app.tex application.tex auth.tex book.tex \ - code.tex config.tex disk_log.tex erl_boot_server.tex \ - erl_ddll.tex erl_prim_loader_stub.tex erlang_stub.tex \ - error_handler.tex error_logger.tex file.tex \ - gen_sctp.tex gen_tcp.tex gen_udp.tex global.tex \ - global_group.tex heart.tex inet.tex inet_res.tex \ - init_stub.tex kernel_app.tex net_adm.tex net_kernel.tex \ - os.tex packages.tex pg2.tex ref_man.tex rpc.tex \ - seq_trace.tex user.tex wrap_log_reader.tex \ - zlib_stub.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index 3b7a710664..e54a427ff0 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -210,6 +210,10 @@ <p><c>net_kernel</c> is currently changing <c>net_ticktime</c> to <c><anno>NetTicktime</anno></c> seconds.</p> </item> + <tag><c>ignored</c></tag> + <item> + <p>The local node is not alive.</p> + </item> </taglist> </desc> </func> diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 42f527f400..ebfe84463a 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1180,10 +1180,27 @@ terminate(Reason, S) -> _ -> ok end, + ShutdownTimeout = + case application:get_env(kernel, shutdown_timeout) of + undefined -> infinity; + {ok,T} -> T + end, foreach(fun({_AppName, Id}) when is_pid(Id) -> + Ref = erlang:monitor(process, Id), + unlink(Id), exit(Id, shutdown), receive + %% Proc died before link {'EXIT', Id, _} -> ok + after 0 -> + receive + {'DOWN', Ref, process, Id, _} -> ok + after ShutdownTimeout -> + exit(Id, kill), + receive + {'DOWN', Ref, process, Id, _} -> ok + end + end end; (_) -> ok end, diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index e3d22e7999..32a12e2b52 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -32,6 +32,8 @@ -import(lists, [foreach/2]). +-define(ANY_NATIVE_CODE_LOADED, any_native_code_loaded). + -record(state, {supervisor, root, path, @@ -97,6 +99,8 @@ init(Ref, Parent, [Root,Mode0]) -> State0 end, + put(?ANY_NATIVE_CODE_LOADED, false), + Parent ! {Ref,{ok,self()}}, loop(State#state{supervisor = Parent}). @@ -1278,20 +1282,35 @@ load_native_code(Mod, Bin) -> %% Therefore we must test for that the loader modules are available %% before trying to to load native code. case erlang:module_loaded(hipe_unified_loader) of - false -> no_native; - true -> hipe_unified_loader:load_native_code(Mod, Bin) + false -> + no_native; + true -> + Result = hipe_unified_loader:load_native_code(Mod, Bin), + case Result of + {module,_} -> + put(?ANY_NATIVE_CODE_LOADED, true); + _ -> + ok + end, + Result end. hipe_result_to_status(Result) -> case Result of - {module,_} -> Result; - _ -> {error,Result} + {module,_} -> + put(?ANY_NATIVE_CODE_LOADED, true), + Result; + _ -> + {error,Result} end. post_beam_load(Mod) -> - case erlang:module_loaded(hipe_unified_loader) of - false -> ok; - true -> hipe_unified_loader:post_beam_load(Mod) + %% post_beam_load/1 can potentially be very expensive because it + %% blocks multi-scheduling; thus we want to avoid the call if we + %% know that it is not needed. + case get(?ANY_NATIVE_CODE_LOADED) of + true -> hipe_unified_loader:post_beam_load(Mod); + false -> ok end. int_list([H|T]) when is_integer(H) -> int_list(T); diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 6cebb7ab97..77ca26b845 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -27,7 +27,8 @@ -include("inet_sctp.hrl"). -export([open/0,open/1,open/2,close/1]). --export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]). +-export([listen/2,peeloff/2]). +-export([connect/4,connect/5,connect_init/4,connect_init/5]). -export([eof/2,abort/2]). -export([send/3,send/4,recv/1,recv/2]). -export([error_string/1]). @@ -109,9 +110,11 @@ open() -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Opts) when is_list(Opts) -> @@ -134,9 +137,11 @@ open(X) -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Port, Opts) when is_integer(Port), is_list(Opts) -> @@ -161,17 +166,38 @@ close(S) -> -spec listen(Socket, IsServer) -> ok | {error, Reason} when Socket :: sctp_socket(), IsServer :: boolean(), + Reason :: term(); + (Socket, Backlog) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Backlog :: integer(), Reason :: term(). -listen(S, Flag) when is_port(S), is_boolean(Flag) -> +listen(S, Backlog) + when is_port(S), is_boolean(Backlog); + is_port(S), is_integer(Backlog) -> case inet_db:lookup_socket(S) of {ok,Mod} -> - Mod:listen(S, Flag); + Mod:listen(S, Backlog); Error -> Error end; listen(S, Flag) -> erlang:error(badarg, [S,Flag]). +-spec peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{} | assoc_id(), + NewSocket :: sctp_socket(), + Reason :: term(). + +peeloff(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + peeloff(S, AssocId); +peeloff(S, AssocId) when is_port(S), is_integer(AssocId) -> + case inet_db:lookup_socket(S) of + {ok,Mod} -> + Mod:peeloff(S, AssocId); + Error -> Error + end. + -spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when Socket :: sctp_socket(), Addr :: inet:ip_address() | inet:hostname(), diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 7d15f8bf83..fa97614eca 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -28,7 +28,7 @@ %% External exports -export([start/0, start_link/0, stop/0, sync/0, sync/1, - safe_whereis_name/1, whereis_name/1, register_name/2, + whereis_name/1, register_name/2, register_name/3, register_name_external/2, register_name_external/3, unregister_name_external/1,re_register_name/2, re_register_name/3, unregister_name/1, registered_names/0, send/2, node_disconnected/1, @@ -203,10 +203,6 @@ send(Name, Msg) -> whereis_name(Name) -> where(Name). --spec safe_whereis_name(term()) -> pid() | 'undefined'. -safe_whereis_name(Name) -> - gen_server:call(global_name_server, {whereis, Name}, infinity). - node_disconnected(Node) -> global_name_server ! {nodedown, Node}. @@ -510,8 +506,7 @@ init([]) -> %% delay can sometimes be quite substantial. Global guarantees that %% the name will eventually be removed, but there is no %% synchronization between nodes; the name can be removed from some -%% node(s) long before it is removed from other nodes. Using -%% safe_whereis_name is no cure. +%% node(s) long before it is removed from other nodes. %% %% - Global cannot handle problems with the distribution very well. %% Depending on the value of the kernel variable 'net_ticktime' long @@ -589,10 +584,6 @@ init([]) -> {'reply', term(), state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({whereis, Name}, From, S) -> - do_whereis(Name, From), - {noreply, S}; - handle_call({registrar, Fun}, From, S) -> S#state.the_registrar ! {trans_all_known, Fun, From}, {noreply, S}; @@ -1235,7 +1226,15 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) -> where(Name) -> case ets:lookup(global_names, Name) of - [{_Name, Pid, _Method, _RPid, _Ref}] -> Pid; + [{_Name, Pid, _Method, _RPid, _Ref}] -> + if node(Pid) == node() -> + case is_process_alive(Pid) of + true -> Pid; + false -> undefined + end; + true -> + Pid + end; [] -> undefined end. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 48a6f3db65..b60c68e3a1 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -36,7 +36,7 @@ -export([i/0, i/1, i/2]). --export([getll/1, getfd/1, open/7, fdopen/5]). +-export([getll/1, getfd/1, open/8, fdopen/6]). -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). @@ -115,7 +115,8 @@ 'mtu' | 'netmask' | 'flags' |'hwaddr'. -type address_family() :: 'inet' | 'inet6'. --type protocol_option() :: 'tcp' | 'udp' | 'sctp'. +-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. +-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. @@ -748,6 +749,8 @@ sctp_opt([Opt|Opts], Mod, R, As) -> sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As); Error -> Error end; + {type,Type} when Type =:= seqpacket; Type =:= stream -> + sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As); binary -> sctp_opt (Opts, Mod, R, As, mode, binary); list -> sctp_opt (Opts, Mod, R, As, mode, list); {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with @@ -996,13 +999,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> Addr :: ip_address(), Port :: port_number(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), - Family :: 'inet' | 'inet6', + Protocol :: socket_protocol(), + Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> - case prim_inet:open(Protocol, Family) of +open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> + case prim_inet:open(Protocol, Family, Type) of {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1029,18 +1033,19 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) -> - fdopen(Fd, Opts, Protocol, Family, Module). +open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) -> + fdopen(Fd, Opts, Protocol, Family, Type, Module). -spec fdopen(Fd :: non_neg_integer(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), + Protocol :: socket_protocol(), Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -fdopen(Fd, Opts, Protocol, Family, Module) -> - case prim_inet:fdopen(Protocol, Fd, Family) of +fdopen(Fd, Opts, Protocol, Family, Type, Module) -> + case prim_inet:fdopen(Protocol, Family, Type, Fd) of {ok, S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1056,18 +1061,24 @@ fdopen(Fd, Opts, Protocol, Family, Module) -> %% socket stat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -i() -> i(tcp), i(udp). +i() -> i(tcp), i(udp), i(sctp). i(Proto) -> i(Proto, [port, module, recv, sent, owner, - local_address, foreign_address, state]). + local_address, foreign_address, state, type]). i(tcp, Fs) -> ii(tcp_sockets(), Fs, tcp); i(udp, Fs) -> - ii(udp_sockets(), Fs, udp). + ii(udp_sockets(), Fs, udp); +i(sctp, Fs) -> + ii(sctp_sockets(), Fs, sctp). ii(Ss, Fs, Proto) -> - LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)], + LLs = + case info_lines(Ss, Fs, Proto) of + [] -> []; + InfoLines -> [h_line(Fs) | InfoLines] + end, Maxs = foldl( fun(Line,Max0) -> smax(Max0,Line) end, duplicate(length(Fs),0),LLs), @@ -1135,6 +1146,7 @@ info(S, F, Proto) -> case prim_inet:gettype(S) of {ok,{_,stream}} -> "STREAM"; {ok,{_,dgram}} -> "DGRAM"; + {ok,{_,seqpacket}} -> "SEQPACKET"; _ -> " " end; fd -> @@ -1186,6 +1198,7 @@ fmt_port(N, Proto) -> %% Return a list of all tcp sockets tcp_sockets() -> port_list("tcp_inet"). udp_sockets() -> port_list("udp_inet"). +sctp_sockets() -> port_list("sctp_inet"). %% Return all ports having the name 'Name' port_list(Name) -> diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl index 5bf3fca647..c47483bbdd 100644 --- a/lib/kernel/src/inet6_sctp.erl +++ b/lib/kernel/src/inet6_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -32,7 +32,8 @@ -define(FAMILY, inet6). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -54,8 +55,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -65,6 +66,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + connect(S, Addr, Port, Opts, Timer) -> inet_sctp:connect(S, Addr, Port, Opts, Timer). diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index cc45f6c7f6..c714b2bee0 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when port=BPort, opts=SockOpts}} when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, Addr, Port, Time) of ok -> {ok,S}; @@ -115,7 +115,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -149,5 +149,5 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE). diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl index e81d417151..ca43c94211 100644 --- a/lib/kernel/src/inet6_udp.erl +++ b/lib/kernel/src/inet6_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ open(Port, Opts) -> port=BPort, opts=SockOpts}} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -84,4 +84,4 @@ controlling_process(Socket, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, udp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE). diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 6f1688c6a2..f8984b13fe 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ -define(INET_AF_ANY, 3). % Fake for ANY in any address family -define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family -%% type codes (gettype, INET_REQ_GETTYPE) +%% type codes to open and gettype - INET_REQ_GETTYPE -define(INET_TYPE_STREAM, 1). -define(INET_TYPE_DGRAM, 2). -define(INET_TYPE_SEQPACKET, 3). @@ -83,16 +83,19 @@ -define(INET_REQ_IFSET, 23). -define(INET_REQ_SUBSCRIBE, 24). -define(INET_REQ_GETIFADDRS, 25). +-define(INET_REQ_ACCEPT, 26). +-define(INET_REQ_LISTEN, 27). %% TCP requests --define(TCP_REQ_ACCEPT, 40). --define(TCP_REQ_LISTEN, 41). +%%-define(TCP_REQ_ACCEPT, 40). MOVED +%%-define(TCP_REQ_LISTEN, 41). MERGED -define(TCP_REQ_RECV, 42). -define(TCP_REQ_UNRECV, 43). -define(TCP_REQ_SHUTDOWN, 44). %% UDP and SCTP requests -define(PACKET_REQ_RECV, 60). --define(SCTP_REQ_LISTEN, 61). +%%-define(SCTP_REQ_LISTEN, 61). MERGED -define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind +-define(SCTP_REQ_PEELOFF, 63). %% subscribe codes, INET_REQ_SUBSCRIBE -define(INET_SUBS_EMPTY_OUT_Q, 1). @@ -100,7 +103,7 @@ %% reply codes for *_REQ_* -define(INET_REP_ERROR, 0). -define(INET_REP_OK, 1). --define(INET_REP_SCTP, 2). +-define(INET_REP, 2). %% INET, TCP and UDP options: -define(INET_OPT_REUSEADDR, 0). @@ -399,6 +402,7 @@ ifaddr, port = 0, fd = -1, + type = seqpacket, opts = [{mode, binary}, {buffer, ?SCTP_DEF_BUFSZ}, {sndbuf, ?SCTP_DEF_BUFSZ}, diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index de74b573bd..2d799d79fa 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,7 +31,8 @@ -define(FAMILY, inet). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -53,8 +54,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -64,6 +65,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + %% A non-blocking connect is implemented when the initial call is to %% gen_sctp:connect_init which passes the value nowait as the Timer connect(S, Addr, Port, Opts, Timer) -> @@ -102,7 +111,7 @@ connect(S, Addr, Port, Opts, Timer) -> connect_get_assoc(S, Addr, Port, false, Timer) -> case recv(S, inet:timeout(Timer)) of - {ok, {Addr, Port, [], #sctp_assoc_change{state=St}=Ev}} -> + {ok, {Addr, Port, _, #sctp_assoc_change{state=St}=Ev}} -> if St =:= comm_up -> %% Yes, successfully connected, return the whole %% sctp_assoc_change event (containing, in particular, @@ -123,7 +132,7 @@ connect_get_assoc(S, Addr, Port, false, Timer) -> connect_get_assoc(S, Addr, Port, Active, Timer) -> Timeout = inet:timeout(Timer), receive - {sctp,S,Addr,Port,{[],#sctp_assoc_change{state=St}=Ev}} -> + {sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} -> case Active of once -> prim_inet:setopt(S, active, once); diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index 6dadccd6a9..4c2db16ce3 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) -> port=BPort, opts=SockOpts}} when ?ip(Ab,Bb,Cb,Db), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, {A,B,C,D}, Port, Time) of ok -> {ok,S}; @@ -117,7 +117,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip(A,B,C,D), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -150,4 +150,4 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 60bd96f332..80d930fe10 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -52,7 +52,7 @@ open(Port, Opts) -> ifaddr=BAddr={A,B,C,D}, port=BPort, opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -93,7 +93,7 @@ controlling_process(Socket, NewOwner) -> fdopen(Fd, Opts) -> inet:fdopen(Fd, optuniquify([{recbuf, ?RECBUF} | Opts]), - udp, inet, ?MODULE). + udp, inet, dgram, ?MODULE). %% Remove all duplicate options from an option list. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 54a63833e6..bded2408a7 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -1 +1,27 @@ -{"%VSN%",[],[]}. +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{"%VSN%", + %% Up from - max two major revisions back + [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + %% Down to - max two major revisions back + [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 +}. diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index c34f2ddeb0..e33b4830ab 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -117,8 +117,9 @@ server1(Iport, Oport, Shell) -> {Curr,Shell1} = case init:get_argument(remsh) of {ok,[[Node]]} -> - RShell = {list_to_atom(Node),shell,start,[]}, - RGr = group:start(self(), RShell), + ANode = list_to_atom(Node), + RShell = {ANode,shell,start,[]}, + RGr = group:start(self(), RShell, rem_sh_opts(ANode)), {RGr,RShell}; E when E =:= error ; E =:= {ok,[[]]} -> {group:start(self(), Shell),Shell} @@ -134,6 +135,9 @@ server1(Iport, Oport, Shell) -> %% Enter the server loop. server_loop(Iport, Oport, Curr, User, Gr). +rem_sh_opts(Node) -> + [{expand_fun,fun(B)-> rpc:call(Node,edlin_expand,expand,[B]) end}]. + %% start_user() %% Start a group leader process and register it as 'user', unless, %% of course, a 'user' already exists. diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 2c5b8ccb66..f469a0af98 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -33,7 +33,7 @@ -export([config_change/1, distr_changed_tc1/1, distr_changed_tc2/1, - shutdown_func/1, do_shutdown/1]). + shutdown_func/1, do_shutdown/1, shutdown_timeout/1]). -define(TESTCASE, testcase_name). -define(testcase, ?config(?TESTCASE, Config)). @@ -50,7 +50,7 @@ all() -> load_use_cache, {group, reported_bugs}, start_phases, script_start, nodedown_start, permit_false_start_local, permit_false_start_dist, get_key, - {group, distr_changed}, config_change, shutdown_func]. + {group, distr_changed}, config_change, shutdown_func, shutdown_timeout]. groups() -> [{reported_bugs, [], @@ -1915,6 +1915,32 @@ do_shutdown(Reason) -> +%%%----------------------------------------------------------------- +%%% Tests the 'shutdown_timeout' kernel config parameter +%%%----------------------------------------------------------------- +shutdown_timeout(Config) when is_list(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Cp1} = start_node(?MODULE_STRING++"_shutdown_timeout"), + wait_for_ready_net(), + ok = rpc:call(Cp1, application, set_env, [kernel, shutdown_timeout, 1000]), + rpc:call(Cp1, code, add_path, [filename:join([DataDir,deadlock])]), + ok = rpc:call(Cp1, application, start, [sasl]), + ok = rpc:call(Cp1, application, start, [deadlock]), + rpc:call(Cp1, deadlock, restart_and_fail, []), + + ok = net_kernel:monitor_nodes(true), + _ = rpc:call(Cp1, init, stop, []), + receive + {nodedown,Cp1} -> + ok + after 10000 -> + ct:fail("timeout 10 sec: node termination hangs") + end, + ok. + + + + %%----------------------------------------------------------------- %% Utility functions %%----------------------------------------------------------------- diff --git a/lib/kernel/test/application_SUITE_data/Makefile.src b/lib/kernel/test/application_SUITE_data/Makefile.src index a237f6badb..abc3c82907 100644 --- a/lib/kernel/test/application_SUITE_data/Makefile.src +++ b/lib/kernel/test/application_SUITE_data/Makefile.src @@ -2,7 +2,8 @@ EFLAGS=+debug_info all: app_start_error.@EMULATOR@ trans_abnormal_sup.@EMULATOR@ \ trans_normal_sup.@EMULATOR@ transient.@EMULATOR@ \ - group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@ + group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@ \ + deadlock/deadlock.@EMULATOR@ app_start_error.@EMULATOR@: app_start_error.erl erlc $(EFLAGS) app_start_error.erl @@ -22,3 +23,5 @@ group_leader.@EMULATOR@: group_leader.erl group_leader_sup.@EMULATOR@: group_leader_sup.erl erlc $(EFLAGS) group_leader_sup.erl +deadlock/deadlock.@EMULATOR@: deadlock/deadlock.erl + erlc $(EFLAGS) -o deadlock deadlock/deadlock.erl
\ No newline at end of file diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app new file mode 100644 index 0000000000..0c1001bed6 --- /dev/null +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app @@ -0,0 +1,8 @@ +{application, deadlock, [ + {vsn, "1"}, + {registered, []}, + {applications, [kernel, stdlib, sasl]}, + {modules, [deadlock]}, + {mod, {deadlock, []}}, + {env, [{fail_start, false}]} +]}. diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl new file mode 100644 index 0000000000..5f68bf9078 --- /dev/null +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl @@ -0,0 +1,69 @@ +-module(deadlock). +-behaviour(application). +-compile(export_all). +-define(SUP,deadlock_sup). +-define(CHILD,deadlock_child). + + +%%%----------------------------------------------------------------- +%%% application callbacks +start(_StartType, _StartArgs) -> + supervisor:start_link({local, ?SUP}, ?MODULE, [sup]). + +stop(_State) -> + ok. + + + +%%%----------------------------------------------------------------- +%%% supervisor callbacks +init([sup]) -> + {ok, {{one_for_one, 5, 10}, [ + { + sasl_syslog_dm, {?MODULE, start_link, []}, + permanent, brutal_kill, worker, + [deadlock] + } + ]}}; + + +%%%----------------------------------------------------------------- +%%% gen_server callbacks +init([child]) -> + case application:get_env(deadlock, fail_start) of + {ok, false} -> + %% we must not fail on the first init, otherwise supervisor + %% terminates immediately + {ok, []}; + {ok, true} -> + timer:sleep(infinity), % init hangs!!!! + {ok, []} + end. + +handle_call(_Req, _From, State) -> + {reply, ok, State}. + +handle_cast(restart, State) -> + {stop, error, State}. + +handle_info(_Msg, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%%----------------------------------------------------------------- +%%% Start child +start_link() -> + gen_server:start_link({local, ?CHILD}, ?MODULE, [child], []). + + +%%%----------------------------------------------------------------- +%%% Provoke hanging +restart_and_fail() -> + application:set_env(deadlock, fail_start, true), % next init will hang + gen_server:cast(?CHILD, restart). diff --git a/lib/kernel/test/erl_boot_server_SUITE.erl b/lib/kernel/test/erl_boot_server_SUITE.erl index cea3715ce4..bb64c01058 100644 --- a/lib/kernel/test/erl_boot_server_SUITE.erl +++ b/lib/kernel/test/erl_boot_server_SUITE.erl @@ -346,7 +346,7 @@ good_hosts(_Config) -> [GoodHost1, GoodHost2, GoodHost3]. open_udp() -> - ?line {ok, S} = prim_inet:open(udp, inet), + ?line {ok, S} = prim_inet:open(udp, inet, dgram), ?line ok = prim_inet:setopts(S, [{mode,list},{active,true}, {deliver,term},{broadcast,true}]), ?line {ok,_} = prim_inet:bind(S, {0,0,0,0}, 0), diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 1b534a5fc4..300152ddce 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -30,33 +30,29 @@ -export( [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, - xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]). + xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, + basic_stream/1, xfer_stream_min/1, peeloff/1, buffers/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, api_open_close, api_listen, api_connect_init, - api_opts, xfer_min, xfer_active, def_sndrcvinfo, - implicit_inet6]. + api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, + basic_stream, xfer_stream_min, peeloff, buffers]. groups() -> []. -init_per_suite(Config) -> - try gen_sctp:open() of +init_per_suite(_Config) -> + case gen_sctp:open() of {ok,Socket} -> gen_sctp:close(Socket), []; - _ -> - [] - catch - error:badarg -> - {skip,"SCTP not supported on this machine"}; - _:_ -> - Config + {error,eprotonosupport} -> + {skip,"SCTP not supported on this machine"} end. -end_per_suite(_Conifig) -> +end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> @@ -96,7 +92,7 @@ xfer_min(Config) when is_list(Config) -> ?line Stream = 0, ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, ?line Loopback = {127,0,0,1}, - ?line {ok,Sb} = gen_sctp:open(), + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), @@ -108,29 +104,44 @@ xfer_min(Config) when is_list(Config) -> inbound_streams=SaInboundStreams, assoc_id=SaAssocId}=SaAssocChange} = gen_sctp:connect(Sa, Loopback, Pb, []), - ?line {ok,{Loopback, - Pa,[], + ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, outbound_streams=SbOutboundStreams, inbound_streams=SbInboundStreams, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line SaOutboundStreams = SbInboundStreams, - ?line SbOutboundStreams = SaInboundStreams, + assoc_id=AssocId}} -> + {AssocId,SbInboundStreams,SbOutboundStreams}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AssocId}} -> + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=AssocId}} = + ?line recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + {AssocId,SbInboundStreams,SbOutboundStreams} + end, + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case gen_sctp:recv(Sb, infinity) of - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok; - {ok,{Loopback, - Pa,[], + ?line case log_ok(gen_sctp:recv(Sb, infinity)) of + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} -> ok; + Event1 -> + {Loopback,Pa, #sctp_paddr_change{addr = {Loopback,_}, state = addr_available, error = 0, - assoc_id = SbAssocId}}} -> + assoc_id = SbAssocId}} = + recv_event(Event1), {ok,{Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, @@ -138,30 +149,40 @@ xfer_min(Config) when is_list(Config) -> Data}} = gen_sctp:recv(Sb, infinity) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), - ?line {ok,{Loopback, - Pb, + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], - Data}} = - gen_sctp:recv(Sa, infinity), + Data} -> + ok; + Event2 -> + {Loopback,Pb, + #sctp_paddr_change{addr={_,Pb}, + state=addr_confirmed, + error=0, + assoc_id=SaAssocId}} = + ?line recv_event(Event2), + ?line {Loopback, + Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + log_ok(gen_sctp:recv(Sa, infinity)) + end, %% ?line ok = gen_sctp:eof(Sa, SaAssocChange), - ?line {ok,{Loopback, - Pa,[], - #sctp_shutdown_event{assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line {ok,{Loopback, - Pb,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SaAssocId}}} = - gen_sctp:recv(Sa, infinity), - ?line {ok,{Loopback, - Pa,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), + ?line {Loopback,Pa,#sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pb, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SaAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), @@ -186,32 +207,52 @@ xfer_active(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open([{active,true}]), ?line {ok,Pa} = inet:port(Sa), - ?line {ok,#sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SaOutboundStreams, - inbound_streams=SaInboundStreams, - assoc_id=SaAssocId}=SaAssocChange} = - gen_sctp:connect(Sa, Loopback, Pb, []), + ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId} = SaAssocChange = + recv_assoc_change(Sa, Loopback, Pb, Timeout), ?line io:format("Sa=~p, Pa=~p, Sb=~p, Pb=~p, SaAssocId=~p, " "SaOutboundStreams=~p, SaInboundStreams=~p~n", [Sa,Pa,Sb,Pb,SaAssocId, SaOutboundStreams,SaInboundStreams]), - ?line SbAssocId = - receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=SBAI}}} -> - ?line SaOutboundStreams = SbInboundStreams, - ?line SaInboundStreams = SbOutboundStreams, - SBAI - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=SbAssocId} = + recv_assoc_change(Sb, Loopback, Pa, Timeout), + ?line SbOutboundStreams = SaInboundStreams, + ?line SbInboundStreams = SaOutboundStreams, ?line io:format("SbAssocId=~p~n", [SbAssocId]), + + ?line case recv_paddr_change(Sa, Loopback, Pb, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + timeout -> ok + end, + ?line case recv_paddr_change(Sb, Loopback, Pa, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=SbAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={Loopback,P}, + error=0, + assoc_id=SbAssocId} -> + ?line match_unless_solaris(Pa, P); + timeout -> ok + end, + ?line [] = flush(), + ?line ok = do_from_other_process( fun () -> gen_sctp:send(Sa, SaAssocId, 0, Data) end), @@ -219,21 +260,9 @@ xfer_active(Config) when is_list(Config) -> {sctp,Sb,Loopback,Pa, {[#sctp_sndrcvinfo{stream=Stream, assoc_id=SbAssocId}], - Data}} -> ok; - {sctp,Sb,Loopback,Pa, - {[], - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}}} -> - ?line receive - {sctp,Sb,Loopback,Pa, - {[#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok - end + Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), ?line receive @@ -242,31 +271,28 @@ xfer_active(Config) when is_list(Config) -> assoc_id=SaAssocId}], Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, %% ?line ok = gen_sctp:abort(Sa, SaAssocChange), - ?line receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SbAssocId}}} -> ok - after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line case recv_assoc_change(Sb, Loopback, Pa, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SbAssocId} -> ok; + timeout -> + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:close(Sb), + ?line case recv_assoc_change(Sa, Loopback, Pb, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SaAssocId} -> ok; + timeout -> + ?line io:format("timeout waiting for comm_lost on Sa~n"), + ?line match_unless_solaris(ok, {timeout,flush()}) + end, ?line receive - {sctp,Sa,Loopback,Pb, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SaAssocId}}} -> ok - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, - ?line receive - {sctp_error,Sa,enotconn} -> ok % Solaris - after 17 -> ok %% Only happens on Solaris - end, + {sctp_error,Sa,enotconn} -> ok % Solaris + after 17 -> ok + end, ?line ok = gen_sctp:close(Sa), %% ?line receive @@ -275,6 +301,30 @@ xfer_active(Config) when is_list(Config) -> end, ok. +recv_assoc_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_assoc_change{}=AssocChange}} -> + AssocChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_assoc_change{assoc_id=AssocId}=AssocChange}} -> + AssocChange + after Timeout -> + timeout + end. + +recv_paddr_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_paddr_change{}=PaddrChange}} -> + PaddrChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_paddr_change{assoc_id=AssocId}=PaddrChange}} -> + PaddrChange + after Timeout -> + timeout + end. + def_sndrcvinfo(doc) -> "Test that #sctp_sndrcvinfo{} parameters set on a socket " "are used by gen_sctp:send/4"; @@ -285,11 +335,11 @@ def_sndrcvinfo(Config) when is_list(Config) -> ?line Data = <<"What goes up, must come down.">>, %% ?line S1 = - ok(gen_sctp:open( + log_ok(gen_sctp:open( 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), ?LOGVAR(S1), ?line P1 = - ok(inet:port(S1)), + log_ok(inet:port(S1)), ?LOGVAR(P1), ?line #sctp_sndrcvinfo{ppid=17, context=0, timetolive=0, assoc_id=0} = getopt(S1, sctp_default_send_param), @@ -297,10 +347,10 @@ def_sndrcvinfo(Config) when is_list(Config) -> gen_sctp:listen(S1, true), %% ?line S2 = - ok(gen_sctp:open()), + log_ok(gen_sctp:open()), ?LOGVAR(S2), ?line P2 = - ok(inet:port(S2)), + log_ok(inet:port(S2)), ?LOGVAR(P2), ?line #sctp_sndrcvinfo{ppid=0, context=0, timetolive=0, assoc_id=0} = getopt(S2, sctp_default_send_param), @@ -309,32 +359,57 @@ def_sndrcvinfo(Config) when is_list(Config) -> state=comm_up, error=0, assoc_id=S2AssocId} = S2AssocChange = - ok(gen_sctp:connect(S2, Loopback, P1, [])), + log_ok(gen_sctp:connect(S2, Loopback, P1, [])), ?LOGVAR(S2AssocChange), - ?line case ok(gen_sctp:recv(S1)) of - {Loopback, P2,[], + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of + {Loopback,P2, #sctp_assoc_change{ + state=comm_up, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId); + {Loopback,P2, + #sctp_paddr_change{ + state=addr_confirmed, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId), + {Loopback,P2, + #sctp_assoc_change{ state=comm_up, error=0, - assoc_id=S1AssocId}} -> - ?LOGVAR(S1AssocId) + assoc_id=S1AssocId}} = + recv_event(log_ok(gen_sctp:recv(S1))) end, + ?line #sctp_sndrcvinfo{ - ppid=17, context=0, timetolive=0, assoc_id=S1AssocId} = + ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} = getopt( S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}), ?line #sctp_sndrcvinfo{ - ppid=0, context=0, timetolive=0, assoc_id=S2AssocId} = + ppid=0, context=0, timetolive=0} = %, assoc_id=S2AssocId} = getopt( S2, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S2AssocId}), %% ?line ok = gen_sctp:send(S1, S1AssocId, 1, <<"1: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=1, ppid=17, context=0, assoc_id=S2AssocId}], - <<"1: ",Data/binary>>} -> ok + <<"1: ",Data/binary>>} -> ok; + Event1 -> + ?line {Loopback,P1, + #sctp_paddr_change{state=addr_confirmed, + addr={_,P1}, + error=0, + assoc_id=S2AssocId}} = + recv_event(Event1), + ?line {Loopback,P1, + [#sctp_sndrcvinfo{ + stream=1, ppid=17, context=0, assoc_id=S2AssocId}], + <<"1: ",Data/binary>>} = + log_ok(gen_sctp:recv(S2)) end, %% ?line ok = @@ -354,7 +429,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line ok = gen_sctp:send(S1, S1AssocId, 0, <<"2: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=0, ppid=19, context=0, assoc_id=S2AssocId}], @@ -362,16 +437,18 @@ def_sndrcvinfo(Config) when is_list(Config) -> end, ?line ok = gen_sctp:send(S2, S2AssocChange, 1, <<"3: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S1)) of + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, assoc_id=S1AssocId}], <<"3: ",Data/binary>>} -> ok; - {Loopback,P2,[], - #sctp_paddr_change{ - addr={Loopback,_}, state=addr_available, - error=0, assoc_id=S1AssocId}} -> - ?line case ok(gen_sctp:recv(S1)) of + Event2 -> + {Loopback,P2, + #sctp_paddr_change{ + addr={Loopback,_}, state=addr_available, + error=0, assoc_id=S1AssocId}} = + recv_event(Event2), + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, @@ -387,7 +464,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> #sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId}, <<"4: ",Data/binary>>) end), - ?line case ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of + ?line case log_ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=0, ppid=20, context=0, assoc_id=S1AssocId}], @@ -416,8 +493,12 @@ getopt(S, Opt, Param) -> setopt(S, Opt, Val) -> inet:setopts(S, [{Opt,Val}]). -ok({ok,X}) -> - io:format("OK: ~p~n", [X]), +log_ok(X) -> log(ok(X)). + +ok({ok,X}) -> X. + +log(X) -> + io:format("LOG[~w]: ~p~n", [self(),X]), X. flush() -> @@ -520,7 +601,10 @@ api_listen(Config) when is_list(Config) -> #sctp_assoc_change{ state=comm_lost}}} = gen_sctp:recv(Sa, infinity); - {error,#sctp_assoc_change{state=cant_assoc}} -> ok + {error,#sctp_assoc_change{state=cant_assoc}} -> + ok%; + %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> + %% ok end, ?line ok = gen_sctp:listen(Sb, true), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -552,29 +636,41 @@ api_connect_init(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open(), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of {error,econnrefused} -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=comm_lost}}} = - gen_sctp:recv(Sa, infinity); + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_lost}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))); ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=cant_assoc}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=cant_assoc}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:listen(Sb, true), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{ - state = comm_up}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_up}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), ok. +recv_event({Addr,Port,[],#sctp_assoc_change{}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_assoc_change{assoc_id=Assoc}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port,[],#sctp_paddr_change{}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_paddr_change{assoc_id=Assoc}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port,[],#sctp_shutdown_event{}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_shutdown_event{assoc_id=Assoc}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}. + api_opts(doc) -> "Test socket options"; api_opts(suite) -> @@ -600,7 +696,7 @@ api_opts(Config) when is_list(Config) -> end. implicit_inet6(Config) when is_list(Config) -> - ?line Hostname = ok(inet:gethostname()), + ?line Hostname = log_ok(inet:gethostname()), ?line case gen_sctp:open(0, [inet6]) of {ok,S1} -> @@ -613,16 +709,16 @@ implicit_inet6(Config) when is_list(Config) -> ?line ok = gen_sctp:close(S1), %% ?line Localhost = - ok(inet:getaddr("localhost", inet6)), + log_ok(inet:getaddr("localhost", inet6)), ?line io:format("~s ~p~n", ["localhost",Localhost]), ?line S2 = - ok(gen_sctp:open(0, [{ip,Localhost}])), + log_ok(gen_sctp:open(0, [{ip,Localhost}])), ?line implicit_inet6(S2, Localhost), ?line ok = gen_sctp:close(S2), %% ?line io:format("~s ~p~n", [Hostname,Host]), ?line S3 = - ok(gen_sctp:open(0, [{ifaddr,Host}])), + log_ok(gen_sctp:open(0, [{ifaddr,Host}])), ?line implicit_inet6(S3, Host), ?line ok = gen_sctp:close(S1); {error,eafnosupport} -> @@ -635,25 +731,159 @@ implicit_inet6(Config) when is_list(Config) -> implicit_inet6(S1, Addr) -> ?line ok = gen_sctp:listen(S1, true), - ?line P1 = ok(inet:port(S1)), - ?line S2 = ok(gen_sctp:open(0, [inet6])), - ?line P2 = ok(inet:port(S2)), + ?line P1 = log_ok(inet:port(S1)), + ?line S2 = log_ok(gen_sctp:open(0, [inet6])), + ?line P2 = log_ok(inet:port(S2)), ?line #sctp_assoc_change{state=comm_up} = - ok(gen_sctp:connect(S2, Addr, P1, [])), - ?line case ok(gen_sctp:recv(S1)) of - {Addr,P2,[],#sctp_assoc_change{state=comm_up}} -> - ok + log_ok(gen_sctp:connect(S2, Addr, P1, [])), + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of + {Addr,P2,#sctp_assoc_change{state=comm_up}} -> + ok; + {Addr,P2,#sctp_paddr_change{state=addr_confirmed, + addr={Addr,P2}, + error=0}} -> + {Addr,P2,#sctp_assoc_change{state=comm_up}} = + recv_event(log_ok(gen_sctp:recv(S1))) end, - ?line case ok(inet:sockname(S1)) of + ?line case log_ok(inet:sockname(S1)) of {Addr,P1} -> ok; {{0,0,0,0,0,0,0,0},P1} -> ok end, - ?line case ok(inet:sockname(S2)) of + ?line case log_ok(inet:sockname(S2)) of {Addr,P2} -> ok; {{0,0,0,0,0,0,0,0},P2} -> ok end, ?line ok = gen_sctp:close(S2). +basic_stream(doc) -> + "Hello world stream socket"; +basic_stream(suite) -> + []; +basic_stream(Config) when is_list(Config) -> + ?line {ok,S} = gen_sctp:open([{type,stream}]), + ?line ok = gen_sctp:listen(S, true), + ?line ok = + do_from_other_process( + fun () -> gen_sctp:listen(S, 10) end), + ?line ok = gen_sctp:close(S), + ok. + +xfer_stream_min(doc) -> + "Minimal data transfer"; +xfer_stream_min(suite) -> + []; +xfer_stream_min(Config) when is_list(Config) -> + ?line Stream = 0, + ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, + ?line Loopback = {127,0,0,1}, + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), + ?line ?LOGVAR(Sb), + ?line {ok,Pb} = inet:port(Sb), + ?line ?LOGVAR(Pb), + ?line ok = gen_sctp:listen(Sb, true), + + ?line {ok,Sa} = gen_sctp:open([{type,stream}]), + ?line ?LOGVAR(Sa), + ?line {ok,Pa} = inet:port(Sa), + ?line ?LOGVAR(Pa), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId_X} = + log_ok(gen_sctp:connect(Sa, Loopback, Pb, [])), + ?line ?LOGVAR(SaAssocId_X), + ?line [{_,#sctp_paddrinfo{assoc_id=SaAssocId,state=active}}] = + log_ok(inet:getopts(Sa, [{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Loopback,Pb}}}])), + ?line ?LOGVAR(SaAssocId), + ?line match_unless_solaris(SaAssocId_X, SaAssocId), + + ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} = + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} -> + {OS,IS,AI}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AI}} -> + {Loopback,Pa, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + {OS,IS,AI} + end, + ?line ?LOGVAR(SbAssocId), + ?line SaOutboundStreams = SbInboundStreams, + ?line ?LOGVAR(SaOutboundStreams), + ?line SbOutboundStreams = SaInboundStreams, + ?line ?LOGVAR(SbOutboundStreams), + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), + ?line case gen_sctp:recv(Sb, infinity) of + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} -> ok; + {ok,{Loopback, + Pa,[], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_available, + error = 0, + assoc_id = SbAssocId}}} -> + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} = gen_sctp:recv(Sb, infinity) + end, + ?line ok = + do_from_other_process( + fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end), + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} -> ok; + Event1 -> + ?line {Loopback,Pb, + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId}} = + recv_event(Event1), + ?line {Loopback,Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + log_ok(gen_sctp:recv(Sa, infinity)) + end, + ?line ok = gen_sctp:close(Sa), + ?line {Loopback,Pa, + #sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line ok = gen_sctp:close(Sb), + + ?line receive + Msg -> test_server:fail({received,Msg}) + after 17 -> ok + end, + ok. + do_from_other_process(Fun) -> @@ -681,3 +911,419 @@ do_from_other_process(Fun) -> {'DOWN',Mref,_,_,Reason} -> erlang:exit(Reason) end. + + + +peeloff(doc) -> + "Peel off an SCTP stream socket"; +peeloff(suite) -> + []; +peeloff(Config) when is_list(Config) -> + ?line Addr = {127,0,0,1}, + ?line Stream = 0, + ?line Timeout = 333, + ?line S1 = socket_open([{ifaddr,Addr}], Timeout), + ?line ?LOGVAR(S1), + ?line P1 = socket_call(S1, get_port), + ?line ?LOGVAR(P1), + ?line Socket1 = socket_call(S1, get_socket), + ?line ?LOGVAR(Socket1), + ?line socket_call(S1, {listen,true}), + ?line S2 = socket_open([{ifaddr,Addr}], Timeout), + ?line ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), + ?line Socket2 = socket_call(S2, get_socket), + ?line ?LOGVAR(Socket2), + %% + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S2Ai), + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S1Ai), + %% + ?line socket_call(S2, {send,S2Ai,Stream,<<"Number one">>}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}), + ?line + receive + {S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), + ?line ?LOGVAR(S3), + ?line P3_X = socket_call(S3, get_port), + ?line ?LOGVAR(P3_X), + ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end, + ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = + socket_call(S3, + {getopts,[{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Addr,P2}}}]}), + %%?line S3Ai = S1Ai, + ?line ?LOGVAR(S3Ai), + %% + ?line socket_call(S3, {send,S3Ai,Stream,<<"Number three">>}), + ?line + receive + {S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, + ?line socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}), + ?line + receive + {S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, + %% + ?line inet:i(sctp), + ?line socket_close_verbose(S1), + ?line socket_close_verbose(S2), + ?line + receive + {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} -> + ?line match_unless_solaris(S3Ai, S3Ai_X) + after Timeout -> + socket_bailout([S3]) + end, + ?line + receive + {S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S3Ai}}} -> ok + after Timeout -> + socket_bailout([S3]) + end, + ?line socket_close_verbose(S3), + ?line [] = flush(), + ok. + + + +buffers(doc) -> + ["Check sndbuf and recbuf behaviour"]; +buffers(suite) -> + []; +buffers(Config) when is_list(Config) -> + ?line Limit = 4096, + ?line Addr = {127,0,0,1}, + ?line Stream = 1, + ?line Timeout = 3333, + ?line S1 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S1), + ?line P1 = socket_call(S1, get_port), + ?line ?LOGVAR(P1), + ?line ok = socket_call(S1, {listen,true}), + ?line S2 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), + %% + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), + ?line Recbuf = + case socket_call(S1, {getopts,[recbuf]}) of + [{recbuf,RB1}] when RB1 >= Limit -> RB1 + end, + ?line Data = mk_data(Recbuf+Limit), + ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}), + ?line socket_call(S2, {send,S2Ai,Stream,Data}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,Data}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line socket_close_verbose(S1), + ?line + receive + {S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line + receive + {S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line socket_close_verbose(S2), + ?line [] = flush(), + ok. + +mk_data(Bytes) -> + mk_data(0, Bytes, <<>>). +%% +mk_data(N, Bytes, Bin) when N < Bytes -> + mk_data(N+4, Bytes, <<Bin/binary,N:32>>); +mk_data(_, _, Bin) -> + Bin. + +%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% socket gen_server ultra light + +socket_open(SocketOpts, Timeout) -> + Opts = [{type,seqpacket},{active,once},binary|SocketOpts], + Starter = + fun () -> + {ok,Socket} = + gen_sctp:open(Opts), + Socket + end, + s_start(Starter, Timeout). + +socket_peeloff(Socket, AssocId, Timeout) -> + Opts = [{active,once},binary], + Starter = + fun () -> + {ok,NewSocket} = + gen_sctp:peeloff(Socket, AssocId), + ok = inet:setopts(NewSocket, Opts), + NewSocket + end, + s_start(Starter, Timeout). + +socket_close_verbose(S) -> + History = socket_history(socket_close(S)), + io:format("socket_close ~p:~n ~p.~n", [S,History]), + History. + +socket_close(S) -> + s_req(S, close). + +socket_call(S, Request) -> + s_req(S, {Request}). + +%% socket_get(S, Key) -> +%% s_req(S, {get,Key}). + +socket_bailout([S|Ss]) -> + History = socket_history(socket_close(S)), + io:format("bailout ~p:~n ~p.~n", [S,History]), + socket_bailout(Ss); +socket_bailout([]) -> + io:format("flush: ~p.~n", [flush()]), + test_server:fail(socket_bailout). + +socket_history({State,Flush}) -> + {lists:keysort( + 2, + lists:flatten( + [[{Key,Val} || Val <- Vals] + || {Key,Vals} <- gb_trees:to_list(State)])), + Flush}. + +s_handler(Socket) -> + fun ({listen,Listen}) -> + ok = gen_sctp:listen(Socket, Listen); + (get_port) -> + ok(inet:port(Socket)); + (get_socket) -> + Socket; + ({connect_init,ConAddr,ConPort,ConOpts}) -> + ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts); + ({send,AssocId,Stream,Data}) -> + ok = gen_sctp:send(Socket, AssocId, Stream, Data); + ({send,OtherSocket,AssocId,Stream,Data}) -> + ok = gen_sctp:send(OtherSocket, AssocId, Stream, Data); + ({setopts,Opts}) -> + ok = inet:setopts(Socket, Opts); + ({getopts,Optnames}) -> + ok(inet:getopts(Socket, Optnames)) + end. + +s_req(S, Req) -> + Mref = erlang:monitor(process, S), + S ! {self(),Mref,Req}, + receive + {'DOWN',Mref,_,_,Error} -> + exit(Error); + {S,Mref,Reply} -> + erlang:demonitor(Mref), + receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end, + Reply + end. + +s_start(Starter, Timeout) -> + Parent = self(), + Owner = + spawn_link( + fun () -> + s_start(Starter(), Timeout, Parent) + end), + Owner. + +s_start(Socket, Timeout, Parent) -> + Handler = s_handler(Socket), + try + s_loop(Socket, Timeout, Parent, Handler, gb_trees:empty()) + catch + Class:Reason -> + Stacktrace = erlang:get_stacktrace(), + io:format(?MODULE_STRING":socket exception ~w:~w at~n" + "~p.~n", [Class,Reason,Stacktrace]), + erlang:raise(Class, Reason, Stacktrace) + end. + +s_loop(Socket, Timeout, Parent, Handler, State) -> + receive + {Parent,Ref,close} -> % socket_close() + erlang:send_after(Timeout, self(), {Parent,Ref,exit}), + s_loop(Socket, Timeout, Parent, Handler, State); + {Parent,Ref,exit} -> + ok = gen_sctp:close(Socket), + Key = exit, + Val = {now(),Socket}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,{NewState,flush()}}; + {Parent,Ref,{Msg}} -> + Result = Handler(Msg), + Key = req, + Val = {now(),{Msg,Result}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,Result}, + s_loop(Socket, Timeout, Parent, Handler, NewState); + %% {Parent,Ref,{get,Key}} -> + %% Parent ! {self(),Ref,gb_get(Key, State)}, + %% s_loop(Socket, Timeout, Parent, Handler, State); + {sctp,Socket,Addr,Port, + {[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}} + when not is_tuple(Data) -> + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port, + #sctp_assoc_change{ + state=comm_up, + inbound_streams=Is}}}|_] + when 0 =< Stream, Stream < Is-> ok; + [] -> ok + end, + Key = {msg,AssocId,Stream}, + Val = {now(),{Addr,Port,SRI,Data}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,AssocId,Stream,Data}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_assoc_change{assoc_id=AssocId,state=St}=SAC}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + Key = {assoc_change,AssocId}, + Val = {now(),{Addr,Port,SAC}}, + case {gb_get(Key, State),St} of + {[],_} -> ok; + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} + when St =:= comm_lost; St =:= shutdown_comp -> ok + end, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,SAC}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_paddr_change{assoc_id=AssocId, + addr={_,P}, + state=St}=SPC}} -> + match_unless_solaris(Port, P), + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case {gb_get({assoc_change,AssocId}, State),St} of + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_], + addr_available} -> ok; + {[],addr_confirmed} -> ok + end, + Key = {paddr_change,AssocId}, + Val = {now(),{Addr,Port,SPC}}, + NewState = gb_push(Key, Val, State), + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_shutdown_event{assoc_id=AssocId}=SSE}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok; + [] -> ok + end, + Key = {shutdown_event,AssocId}, + Val = {now(),{Addr,Port}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(), {Addr,Port,SSE}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + Unexpected -> + erlang:error({unexpected,Unexpected}) + end. + +again(Socket) -> + inet:setopts(Socket, [{active,once}]). + +gb_push(Key, Val, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + gb_trees:insert(Key, [Val], GBT); + {value,V} -> + gb_trees:update(Key, [Val|V], GBT) + end. + +gb_get(Key, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + []; + {value,V} -> + V + end. + +match_unless_solaris(A, B) -> + case os:type() of + {unix,sunos} -> B; + _ -> A = B + end. diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 514deaf065..2354f8accd 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -99,9 +99,9 @@ buffer_size(Config) when is_list(Config) -> ?line Bin = list_to_binary(lists:seq(0, Len-1)), ?line M = 8192 div Len, ?line Spec0 = - [{opt,M},{safe,M-1},{long,M+1}, - {opt,2*M},{safe,2*M-1},{long,2*M+1}, - {opt,4*M},{safe,4*M-1},{long,4*M+1}], + [{opt,M},{safe,M-3},{long,M+1}, + {opt,2*M},{safe,2*M-3},{long,2*M+1}, + {opt,4*M},{safe,4*M-3},{long,4*M+1}], ?line Spec = [case Tag of opt -> @@ -145,16 +145,27 @@ buffer_size_client(_, _, _, _, _, []) -> ?line ok; buffer_size_client(Server, IP, Port, Socket, Cnt, [Opts|T]) when is_list(Opts) -> + ?line io:format("buffer_size_client Cnt=~w setopts ~p.~n", [Cnt,Opts]), ?line ok = inet:setopts(Socket, Opts), ?line Server ! {self(),setopts,Cnt}, ?line receive {Server,setopts,Cnt} -> ok end, ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T); buffer_size_client(Server, IP, Port, - Socket, Cnt, [{B,Replies}|T]) when is_binary(B) -> - ?line ok = gen_udp:send(Socket, IP, Port, B), + Socket, Cnt, [{B,Replies}|T]=Opts) when is_binary(B) -> + ?line io:format( + "buffer_size_client Cnt=~w send size ~w expecting ~p.~n", + [Cnt,size(B),Replies]), + ?line ok = gen_udp:send(Socket, IP, Port, <<Cnt,B/binary>>), ?line receive {Server,Cnt,Reply} -> - ?line case lists:member(Reply, Replies) of + ?line Tag = + if + is_tuple(Reply) -> + element(1, Reply); + is_atom(Reply) -> + Reply + end, + ?line case lists:member(Tag, Replies) of true -> ok; false -> ?line @@ -162,34 +173,62 @@ buffer_size_client(Server, IP, Port, byte_size(B), inet:getopts(Socket, [sndbuf,recbuf])}) - end - end, - ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T). + end, + ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T) + after 1313 -> + ?line buffer_size_client(Server, IP, Port, Socket, Cnt, Opts) + end. buffer_size_server(_, _, _, _, _, []) -> ok; buffer_size_server(Client, IP, Port, Socket, Cnt, [Opts|T]) when is_list(Opts) -> receive {Client,setopts,Cnt} -> ok end, + ?line io:format("buffer_size_server Cnt=~w setopts ~p.~n", [Cnt,Opts]), ok = inet:setopts(Socket, Opts), Client ! {self(),setopts,Cnt}, buffer_size_server(Client, IP, Port, Socket, Cnt+1, T); buffer_size_server(Client, IP, Port, Socket, Cnt, [{B,_}|T]) when is_binary(B) -> + ?line io:format( + "buffer_size_server Cnt=~w expecting size ~w.~n", + [Cnt,size(B)]), Client ! {self(),Cnt, - receive - {udp,Socket,IP,Port,D} when is_binary(D) -> + case buffer_size_server_recv(Socket, IP, Port, Cnt) of + D when is_binary(D) -> SizeD = byte_size(D), + ?line io:format( + "buffer_size_server Cnt=~w received size ~w.~n", + [Cnt,SizeD]), case B of - D -> correct; - <<D:SizeD/binary,_/binary>> -> truncated + D -> + correct; + <<D:SizeD/binary,_/binary>> -> + truncated; + _ -> + {unexpected,D} end; - {udp_error,Socket,Error} -> Error - after 5000 -> timeout + Error -> + ?line io:format( + "buffer_size_server Cnt=~w received error ~w.~n", + [Cnt,Error]), + Error end}, buffer_size_server(Client, IP, Port, Socket, Cnt+1, T). +buffer_size_server_recv(Socket, IP, Port, Cnt) -> + receive + {udp,Socket,IP,Port,<<Cnt,B/binary>>} -> + B; + {udp,Socket,IP,Port,<<_/binary>>} -> + buffer_size_server_recv(Socket, IP, Port, Cnt); + {udp_error,Socket,Error} -> + Error + after 5000 -> + {timeout,flush()} + end. + %%------------------------------------------------------------- diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 1e7bcf1766..60035b50a0 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -436,7 +436,7 @@ lock_global2(Id, Parent) -> %cp1 - cp3 are started, and the name 'test' registered for a process on %test_server. Then it is checked that the name is registered on all -%nodes, using whereis_name and safe_whereis_name. Check that the same +%nodes, using whereis_name. Check that the same %name can't be registered with another value. Exit the registered %process and check that the name disappears. Register a new process %(Pid2) under the name 'test'. Let another new process (Pid3) @@ -465,10 +465,6 @@ names(Config) when is_list(Config) -> % test that it is registered at all nodes ?line ?UNTIL(begin - (Pid =:= global:safe_whereis_name(test)) and - (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and (Pid =:= global:whereis_name(test)) and (Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and (Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and @@ -566,10 +562,7 @@ names_hidden(Config) when is_list(Config) -> % Check that it didn't get registered on visible nodes ?line - ?UNTIL((undefined =:= global:safe_whereis_name(test)) and - (undefined =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (undefined =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (undefined =:= global:whereis_name(test)) and + ?UNTIL((undefined =:= global:whereis_name(test)) and (undefined =:= rpc:call(Cp1, global, whereis_name, [test])) and (undefined =:= rpc:call(Cp2, global, whereis_name, [test]))), @@ -579,11 +572,7 @@ names_hidden(Config) when is_list(Config) -> % test that it is registered at all nodes ?line - ?UNTIL((Pid =:= global:safe_whereis_name(test)) and - (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (HPid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and - (Pid =:= global:whereis_name(test)) and + ?UNTIL((Pid =:= global:whereis_name(test)) and (Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and (Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and (HPid =:= rpc:call(Cp3, global, whereis_name, [test])) and diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 8a3d220e46..15b0ed5718 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -136,21 +136,22 @@ ns_init(ZoneDir, PrivDir, DataDir) -> atom_to_list(ZoneDir)]}, stderr_to_stdout, eof]), - ns_start(ZoneDir, NS, P); + ns_start(ZoneDir, PrivDir, NS, P); _ -> throw("Only run on Unix") end. -ns_start(ZoneDir, NS, P) -> +ns_start(ZoneDir, PrivDir, NS, P) -> case ns_collect(P) of eof -> erlang:error(eof); "Running: "++_ -> {ZoneDir,NS,P}; "Error: "++Error -> + ns_printlog(filename:join([PrivDir,ZoneDir,"named.log"])), throw(Error); _ -> - ns_start(ZoneDir, NS, P) + ns_start(ZoneDir, PrivDir, NS, P) end. ns_end(undefined, _PrivDir) -> undefined; diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named index 7caa3756ef..39e7b1d5aa 100755 --- a/lib/kernel/test/inet_res_SUITE_data/run-named +++ b/lib/kernel/test/inet_res_SUITE_data/run-named @@ -47,6 +47,7 @@ CONF_FILE=named.conf INC_FILE=named_inc.conf PID_FILE=named.pid LOG_FILE=named.log +EXIT_FILE=named.exit error () { r=$? @@ -71,10 +72,14 @@ test -d "$SRCDIR" || \ test -f "$SRCDIR/$INC_FILE" || \ error "Missing file: $SRCDIR/$INC_FILE !" -# Locate named and check version +# Locate named and check version. +# The bind-named name is used for tricking Apparmor and such +# by copying/hardlinking the real named to that name. NAMED=named -for n in /usr/sbin/named /usr/sbin/in.named; do - test -x "$n" && NAMED="$n" +for n in /usr/local/bin/bind-named /usr/local/bin/named \ + /usr/sbin/bind-named /usr/sbin/named /usr/sbin/in.named +do + test -x "$n" && NAMED="$n" && break done NAMED_VER="`"$NAMED" -v 2>&1`" || \ error "Name server not found!" @@ -145,19 +150,27 @@ cat >>"$CONF_FILE" <<-CONF_FILE ( cd "$SRCDIR" && ls -1 ) | while read f; do cp -fp "$SRCDIR/$f" . done +rm -f "$EXIT_FILE" # Start nameserver echo "Cwd: `pwd`" echo "Nameserver: $NAMED_VER" echo "Port: $2" echo "ZoneDir: $3" -$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null & -NAMED=$! -trap "kill -TERM $NAMED >/dev/null 2>&1; wait $NAMED >/dev/null 2>&1" \ +echo "Command: $NAMED $NAMED_FG -c $CONF_FILE" +($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \ + echo "$?" >"$EXIT_FILE")& +NAMED_PID=$! +trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ 0 1 2 3 15 sleep 2 # Give name server time to load its zone files -echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED]..." -while read LINE; do - test :"$LINE" = :'quit' && break -done +if [ -f "$EXIT_FILE" ]; then + ERROR="`cat "$EXIT_FILE"`" + (exit "$ERROR")& error "$NAMED returned $ERROR on start" +else + echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..." + while read LINE; do + test :"$LINE" = :'quit' && break + done +fi echo "Closing: Terminating nameserver..." diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl index 16b6c54939..0f29d895e5 100644 --- a/lib/kernel/test/kernel_SUITE.erl +++ b/lib/kernel/test/kernel_SUITE.erl @@ -32,7 +32,7 @@ -export([init_per_testcase/2, end_per_testcase/2]). % Test cases must be exported. --export([app_test/1]). +-export([app_test/1, appup_test/1]). %% %% all/1 @@ -40,7 +40,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app_test]. + [app_test, appup_test]. groups() -> []. @@ -76,3 +76,63 @@ app_test(suite) -> app_test(Config) when is_list(Config) -> ?line ok=?t:app_test(kernel), ok. + + +%% Test that appup allows upgrade from/downgrade to a maximum of two +%% major releases back. +appup_test(_Config) -> + application:load(kernel), + {_,_,Vsn} = lists:keyfind(kernel,1,application:loaded_applications()), + AppupFile = filename:join([code:lib_dir(kernel),ebin,"kernel.appup"]), + {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile), + ct:log("~p~n",[AppupScript]), + {OkVsns,NokVsns} = create_test_vsns(Vsn), + check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), + check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + check_appup(NokVsns,UpFrom,error), + check_appup(NokVsns,DownTo,error), + ok. + +create_test_vsns(Current) -> + [XStr,YStr|Rest] = string:tokens(Current,"."), + X = list_to_integer(XStr), + Y = list_to_integer(YStr), + SecondMajor = vsn(X,Y-2), + SecondMinor = SecondMajor ++ ".1.3", + FirstMajor = vsn(X,Y-1), + FirstMinor = FirstMajor ++ ".57", + ThisMajor = vsn(X,Y), + This = + case Rest of + [] -> + []; + ["1"] -> + [ThisMajor]; + _ -> + ThisMinor = ThisMajor ++ ".1", + [ThisMajor,ThisMinor] + end, + OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], + + ThirdMajor = vsn(X,Y-3), + ThirdMinor = ThirdMajor ++ ".10.12", + Illegal = ThisMajor ++ ",1", + Newer1Major = vsn(X,Y+1), + Newer1Minor = Newer1Major ++ ".1", + Newer2Major = ThisMajor ++ "1", + NokVsns = [ThirdMajor,ThirdMinor, + Illegal, + Newer1Major,Newer1Minor, + Newer2Major], + {OkVsns,NokVsns}. + +vsn(X,Y) -> + integer_to_list(X) ++ "." ++ integer_to_list(Y). + +check_appup([Vsn|Vsns],Instrs,Expected) -> + case systools_relup:appup_search_for_version(Vsn, Instrs) of + Expected -> check_appup(Vsns,Instrs,Expected); + Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other}) + end; +check_appup([],_,_) -> + ok. diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl index 0ac34e735c..520b53b4e4 100644 --- a/lib/kernel/test/pg2_SUITE.erl +++ b/lib/kernel/test/pg2_SUITE.erl @@ -47,6 +47,7 @@ init_per_testcase(Case, Config) -> [{?TESTCASE, Case}, {watchdog, Dog} | Config]. end_per_testcase(_Case, _Config) -> + test_server_ctrl:kill_slavenodes(), Dog = ?config(watchdog, _Config), test_server:timetrap_cancel(Dog), ok. diff --git a/lib/megaco/.gitignore b/lib/megaco/.gitignore new file mode 100644 index 0000000000..1c5979cd62 --- /dev/null +++ b/lib/megaco/.gitignore @@ -0,0 +1,3 @@ +examples/meas/Makefile +examples/meas/meas.sh.skel +examples/meas/mstone1.sh.skel diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in index 8f94a4efcf..b88e17ec85 100644 --- a/lib/megaco/configure.in +++ b/lib/megaco/configure.in @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*- dnl dnl %CopyrightBegin% dnl -dnl Copyright Ericsson AB 2001-2010. All Rights Reserved. +dnl Copyright Ericsson AB 2001-2011. All Rights Reserved. dnl dnl The contents of this file are subject to the Erlang Public License, dnl Version 1.1, (the "License"); you may not use this file except in @@ -273,5 +273,6 @@ if test "$PERL" = no_perl; then AC_MSG_ERROR([Perl is required to build the flex scanner!]) fi +AC_OUTPUT(examples/meas/Makefile:examples/meas/Makefile.in) AC_OUTPUT(src/flex/$host/Makefile:src/flex/Makefile.in) diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile index 4b3c117b20..f782afc3f6 100644 --- a/lib/megaco/doc/src/Makefile +++ b/lib/megaco/doc/src/Makefile @@ -27,14 +27,6 @@ VSN=$(MEGACO_VSN) APPLICATION=megaco # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -73,35 +65,10 @@ EXTRA_FILES = \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi $(APP_FILE) - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - - -TOP_HTML_FILES = $(INDEX_TARGET) - -endif - INDEX_FILE = index.html INDEX_SRC = $(INDEX_FILE).src INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE) @@ -131,8 +98,6 @@ $(HTMLDIR)/%.jpg: %.jpg $(HTMLDIR)/%.png: %.png $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man ldocs: local_docs $(INDEX_TARGET) @@ -147,41 +112,6 @@ clean clean_docs: clean_html clean_man rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html imgs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: imgs $(HTML_FILES) $(TOP_HTML_FILES) - -mhtml: html $(HTML_REF3_FILES) $(HTML_CHAPTER_FILES) - -clean: clean_html clean_man clean_pdf - rm -f core *~ - rm -f *.aux *.cites *.citeshd *.dvi *.idx *.ilg *.ind - rm -f *.indhd *.lof *.lofhd *.lot *.lothd *.otpdef - rm -f *.otpuse *.terms *.termshd *.toc *.makeindexlog *.dvipslog - rm -f *.bib *.bbl *.blg *.bibhd - -clean_pdf: - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f $(TEX_FILES_USERS_GUIDE) - rm -f $(TEX_FILES_REF_MAN) - rm -f $(TEX_FILES_BOOK) - -endif - clean_man: rm -f $(MAN3DIR)/* @@ -203,8 +133,6 @@ debug opt: info: @echo "->Makefile<-" @echo "" - @echo "DOCSUPPORT = $(DOCSUPPORT)" - @echo "" @echo "INDEX_FILE = $(INDEX_FILE)" @echo "INDEX_SRC = $(INDEX_SRC)" @echo "INDEX_TARGET = $(INDEX_TARGET)" @@ -216,10 +144,6 @@ info: @echo "" @echo "IMG_FILES = $(IMG_FILES)" @echo "" - @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)" - @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)" - @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)" - @echo "" @echo "MAN3_FILES = $(MAN3_FILES)" @echo "" @echo "HTML_FILES = $(HTML_FILES)" @@ -236,8 +160,6 @@ info: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -250,33 +172,6 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/standard $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(IMG_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(TOP_HTML_FILES) $(RELSYSDIR)/doc - $(INSTALL_DIR) $(RELSYSDIR)/doc/standard - $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard -endif -endif - -endif - release_spec: $(HTMLDIR)/megaco_architecture.html: megaco_architecture.xml diff --git a/lib/megaco/doc/src/make.dep b/lib/megaco/doc/src/make.dep deleted file mode 100644 index 0e2040ab50..0000000000 --- a/lib/megaco/doc/src/make.dep +++ /dev/null @@ -1,59 +0,0 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode - -# %CopyrightBegin% -# -# Copyright Ericsson AB 2001-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# 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 online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% - -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex megaco.tex megaco_architecture.tex \ - megaco_codec_meas.tex \ - megaco_codec_mstone1.tex megaco_codec_mstone2.tex \ - megaco_codec_transform.tex \ - megaco_debug.tex megaco_edist_compress.tex \ - megaco_encode.tex megaco_encoder.tex megaco_examples.tex \ - megaco_flex_scanner.tex megaco_intro.tex megaco_mib.tex \ - megaco_performance.tex megaco_run.tex megaco_tcp.tex \ - megaco_transport.tex megaco_transport_mechanisms.tex \ - megaco_udp.tex megaco_user.tex part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: call_flow.ps call_flow_cont.ps distr_node_config.ps \ - megaco_sys_arch.ps single_node_config.ps - -book.dvi: mstone1.ps - -book.dvi: MG-startup_flow_noMID.ps MGC_startup_call_flow.ps \ - MG_startup_call_flow.ps - diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml index 2aba8db71b..baf8c6a201 100644 --- a/lib/megaco/doc/src/notes.xml +++ b/lib/megaco/doc/src/notes.xml @@ -36,6 +36,61 @@ section is the version number of Megaco.</p> + <section><title>Megaco 3.15.1.2</title> + + <p>Version 3.15.1.2 supports code replacement in runtime from/to + version 3.15.1.1, 3.15.1 and 3.15.</p> + + <section> + <title>Improvements and new features</title> + +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Minor improvemnts to the emasurement tool mstone1. </p> + <p>Own Id: OTP-9604</p> + </item> + + <item> + <p>ASN.1 no longer makes use of a driver to accelerate encode/decode, + instead it uses NIFs. The encoding config option is <em>still</em> + the same, i.e. <c>driver</c>. </p> + <p>Own Id: OTP-9672</p> + </item> + + <item> + <p>The profiling test tool has been rewritten. </p> + <p>Håkan Mattsson</p> + <p>Own Id: OTP-9679</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed bugs and malfunctions</title> + + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>Fixing miscellaneous things detected by dialyzer. </p> + <p>Own Id: OTP-9075</p> + </item> + + </list> + --> + + </section> + + </section> <!-- 3.15.1.2 --> + + <section><title>Megaco 3.15.1.1</title> <p>Version 3.15.1.1 supports code replacement in runtime from/to diff --git a/lib/megaco/examples/meas/Makefile b/lib/megaco/examples/meas/Makefile.in index 0a6cbb44a6..6af7ef6c65 100644 --- a/lib/megaco/examples/meas/Makefile +++ b/lib/megaco/examples/meas/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# Copyright Ericsson AB 2002-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -35,12 +35,19 @@ VSN=$(MEGACO_VSN) # ---------------------------------------------------- +# Configured variables +# ---------------------------------------------------- +PERL = @PERL@ + + +# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN) EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples MEAS_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/meas + # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- @@ -49,9 +56,13 @@ include modules.mk ERL_FILES = $(MODULES:%=%.erl) -TARGET_FILES = \ +SCRIPT_SKELETONS = $(SCRIPT_SKELETON_SRC:%.src=%) + +ERL_TARGETS = \ $(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) +TARGET_FILES = $(SCRIPT_SKELETONS) $(ERL_TARGETS) + # ---------------------------------------------------- # FLAGS @@ -91,12 +102,27 @@ debug: opt: $(TARGET_FILES) +script_skeletons: $(SCRIPT_SKELETONS) + +info: + @echo "MODULES = $(MODULES)" + @echo "ERL_FILED = $(ERL_FILES)" + @echo "" + @echo "SCRIPT_SKELETON_SRC = $(SCRIPT_SKELETON_SRC)" + @echo "SCRIPT_SKELETONS = $(SCRIPT_SKELETONS)" + @echo "" + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + clean: rm -f $(TARGET_FILES) rm -f errs core *~ docs: +conf: + cd ../..; $(MAKE) conf + # ---------------------------------------------------- # Release Target @@ -120,6 +146,14 @@ release_docs_spec: # Include dependencies # ---------------------------------------------------- +meas.sh.skel: meas.sh.skel.src + @echo "transforming $< to $@" + $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@ + +mstone1.sh.skel: mstone1.sh.skel.src + @echo "transforming $< to $@" + $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@ + megaco_codec_transform.$(EMULATOR): megaco_codec_transform.erl megaco_codec_meas.$(EMULATOR): megaco_codec_meas.erl diff --git a/lib/megaco/examples/meas/meas.sh.skel b/lib/megaco/examples/meas/meas.sh.skel.src index 76745ed8f4..c7bd6cdd2a 100644 --- a/lib/megaco/examples/meas/meas.sh.skel +++ b/lib/megaco/examples/meas/meas.sh.skel.src @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2010. All Rights Reserved. +# Copyright Ericsson AB 2007-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ # ERL_HOME=<path to otp top dir> -MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir> +MEGACO_HOME=$ERL_HOME/lib/erlang/lib/megaco-%VSN% MEAS_HOME=$MEGACO_HOME/examples/meas PATH=$ERL_HOME/bin:$PATH diff --git a/lib/megaco/examples/meas/modules.mk b/lib/megaco/examples/meas/modules.mk index 8f1b45c8a6..26979933d7 100644 --- a/lib/megaco/examples/meas/modules.mk +++ b/lib/megaco/examples/meas/modules.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# Copyright Ericsson AB 2002-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,9 +17,9 @@ # # %CopyrightEnd% -SCRIPT_SKELETONS = \ - meas.sh.skel \ - mstone1.sh.skel +SCRIPT_SKELETON_SRC = \ + meas.sh.skel.src \ + mstone1.sh.skel.src MESSAGE_PACKAGES = \ time_test.msgs diff --git a/lib/megaco/examples/meas/mstone1.sh.skel b/lib/megaco/examples/meas/mstone1.sh.skel.src index b7c7e41007..54a6c61a58 100644 --- a/lib/megaco/examples/meas/mstone1.sh.skel +++ b/lib/megaco/examples/meas/mstone1.sh.skel.src @@ -3,7 +3,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2009. All Rights Reserved. +# Copyright Ericsson AB 2007-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -59,7 +59,7 @@ Options: " ERL_HOME=<path to otp top dir> -MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir> +MEGACO_HOME=$ERL_HOME/lib/erlang/lib/megaco-%VSN% MEAS_HOME=$MEGACO_HOME/examples/meas PATH=$ERL_HOME/bin:$PATH diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src index 7107178d1a..7f6fe0c733 100644 --- a/lib/megaco/src/app/megaco.appup.src +++ b/lib/megaco/src/app/megaco.appup.src @@ -139,10 +139,17 @@ %% | %% v %% 3.15.1.1 +%% | +%% v +%% 3.15.1.2 %% %% {"%VSN%", [ + {"3.15.1.1", + [ + ] + }, {"3.15.1", [ ] @@ -160,6 +167,10 @@ } ], [ + {"3.15.1.1", + [ + ] + }, {"3.15.1", [ ] diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk index d12bd8bad0..c9ca34bcf6 100644 --- a/lib/megaco/src/binary/depend.mk +++ b/lib/megaco/src/binary/depend.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# Copyright Ericsson AB 2001-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -24,9 +24,9 @@ # but for per_bin it means that a stage in the encode # is done in the asn1 driver. # -# +driver +# +nif # For ber_bin this means that part of the decode is done -# in the asn1 driver. +# in the asn1 nif. # # +asn1config # This is only used by the ber_bin, and means that @@ -45,22 +45,22 @@ endif BER_V1_FLAGS = $(ASN1_CT_OPTS) BER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif BER_V2_FLAGS = $(ASN1_CT_OPTS) BER_BIN_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif BER_PREV3A_FLAGS = $(ASN1_CT_OPTS) BER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif BER_PREV3B_FLAGS = $(ASN1_CT_OPTS) BER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif BER_PREV3C_FLAGS = $(ASN1_CT_OPTS) BER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif BER_V3_FLAGS = $(ASN1_CT_OPTS) BER_BIN_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize -BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver +BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif PER_V1_FLAGS = $(ASN1_CT_OPTS) PER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) PER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +optimize diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl index 3a548c4d9e..e9c19605dd 100644 --- a/lib/megaco/test/megaco_codec_v1_test.erl +++ b/lib/megaco/test/megaco_codec_v1_test.erl @@ -371,9 +371,9 @@ profile_decode_text_messages(Slogan, Codec, Config, Msgs0) -> decode_text_messages(Codec, Config, Bins, []) end, %% Make a dry run, just to make sure all modules are loaded: - io:format("make a dry run..~n", []), + io:format("make a dry run...~n", []), (catch Fun()), - io:format("make the run..~n", []), + io:format("make the run...~n", []), megaco_profile:profile(Slogan, Fun). %% (catch megaco_codec_v1_test:profile_encode_compact_text_messages()). diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl index c3a80febba..1d3fcb36e9 100644 --- a/lib/megaco/test/megaco_codec_v2_test.erl +++ b/lib/megaco/test/megaco_codec_v2_test.erl @@ -346,9 +346,9 @@ profile_decode_text_messages(Slogan, Codec, Config, Msgs0) -> decode_text_messages(Codec, Config, Bins, []) end, %% Make a dry run, just to make sure all modules are loaded: - io:format("make a dry run..~n", []), + io:format("make a dry run...~n", []), (catch Fun()), - io:format("make the run..~n", []), + io:format("make the run...~n", []), megaco_profile:profile(Slogan, Fun). %% (catch megaco_codec_v2_test:profile_encode_compact_text_messages()). diff --git a/lib/megaco/test/megaco_mess_test.erl b/lib/megaco/test/megaco_mess_test.erl index ded1506271..383e3df774 100644 --- a/lib/megaco/test/megaco_mess_test.erl +++ b/lib/megaco/test/megaco_mess_test.erl @@ -34,12 +34,12 @@ %% -compile(export_all). -export([ - all/0,groups/0,init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, + all/0, groups/0, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2, connect/1, - request_and_reply_plain/1, request_and_no_reply/1, @@ -347,39 +347,83 @@ end_per_testcase(Case, Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> - [connect, {group, request_and_reply}, - {group, pending_ack}, dist, {group, tickets}]. + [ + connect, + {group, request_and_reply}, + {group, pending_ack}, + dist, + {group, tickets} + ]. groups() -> - [{request_and_reply, [], - [request_and_reply_plain, request_and_no_reply, + [ + {request_and_reply, [], + [request_and_reply_plain, + request_and_no_reply, request_and_reply_pending_ack_no_pending, request_and_reply_pending_ack_one_pending, single_trans_req_and_reply, single_trans_req_and_reply_sendopts, - request_and_reply_and_ack, request_and_reply_and_no_ack, + request_and_reply_and_ack, + request_and_reply_and_no_ack, request_and_reply_and_late_ack, trans_req_and_reply_and_req]}, {pending_ack, [], [pending_ack_plain, request_and_pending_and_late_reply]}, {tickets, [], - [otp_4359, otp_4836, otp_5805, otp_5881, otp_5887, - otp_6253, otp_6275, otp_6276, {group, otp_6442}, - {group, otp_6865}, otp_7189, otp_7259, otp_7713, - {group, otp_8183}, otp_8212]}, + [otp_4359, + otp_4836, + otp_5805, + otp_5881, + otp_5887, + otp_6253, + otp_6275, + otp_6276, + {group, otp_6442}, + {group, otp_6865}, + otp_7189, + otp_7259, + otp_7713, + {group, otp_8183}, + otp_8212]}, {otp_6442, [], - [otp_6442_resend_request1, otp_6442_resend_request2, - otp_6442_resend_reply1, otp_6442_resend_reply2]}, + [otp_6442_resend_request1, + otp_6442_resend_request2, + otp_6442_resend_reply1, + otp_6442_resend_reply2]}, {otp_6865, [], [otp_6865_request_and_reply_plain_extra1, otp_6865_request_and_reply_plain_extra2]}, - {otp_8183, [], [otp_8183_request1]}]. + {otp_8183, [], [otp_8183_request1]} + ]. + + +init_per_suite(Config) -> + io:format("~w:init_per_suite -> entry with" + "~n Config: ~p" + "~n", [?MODULE, Config]), + Config. + +end_per_suite(_Config) -> + io:format("~w:end_per_suite -> entry with" + "~n _Config: ~p" + "~n", [?MODULE, _Config]), + ok. + init_per_group(_GroupName, Config) -> + io:format("~w:init_per_group -> entry with" + "~n _GroupName: ~p" + "~n Config: ~p" + "~n", [?MODULE, _GroupName, Config]), Config. end_per_group(_GroupName, Config) -> + io:format("~w:end_per_group -> entry with" + "~n _GroupName: ~p" + "~n Config: ~p" + "~n", [?MODULE, _GroupName, Config]), Config. @@ -394,12 +438,16 @@ connect(Config) when is_list(Config) -> PrelMid = preliminary_mid, MgMid = ipv4_mid(4711), + d("connect -> start megaco app",[]), ?VERIFY(ok, application:start(megaco)), + d("connect -> start (MG) user ~p",[MgMid]), ?VERIFY(ok, megaco:start_user(MgMid, [{send_mod, bad_send_mod}, {request_timer, infinity}, {reply_timer, infinity}])), + d("connect -> get receive info for ~p",[MgMid]), MgRH = user_info(MgMid, receive_handle), + d("connect -> (MG) try connect to MGC",[]), {ok, PrelCH} = ?VERIFY({ok, _}, megaco:connect(MgRH, PrelMid, sh, self())), connections([PrelCH]), @@ -6776,16 +6824,12 @@ rapalr_mg_notify_request_ar(Rid, Tid, Cid) -> - - - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% dist(suite) -> []; dist(Config) when is_list(Config) -> + ?SKIP("Needs a re-write..."), [_Local, Dist] = ?ACQUIRE_NODES(2, Config), d("dist -> start proxy",[]), megaco_mess_user_test:start_proxy(), @@ -6897,7 +6941,11 @@ dist(Config) when is_list(Config) -> ?VERIFY(ok, application:stop(megaco)), ?RECEIVE([]), - d("dist -> done",[]), + + d("dist -> stop proxy",[]), + megaco_mess_user_test:stop_proxy(), + + d("dist -> done", []), ok. diff --git a/lib/megaco/test/megaco_profile.erl b/lib/megaco/test/megaco_profile.erl index d0b62610e1..344c551970 100644 --- a/lib/megaco/test/megaco_profile.erl +++ b/lib/megaco/test/megaco_profile.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,50 +24,102 @@ -module(megaco_profile). --export([profile/2]). - +-export([profile/2, prepare/2, analyse/1, + fprof_to_calltree/1, fprof_to_calltree/2, fprof_to_calltree/3]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Execute Fun and profile it with fprof. -profile(Slogan, Fun) when is_function(Fun) -> +profile(Slogan, Fun) when is_function(Fun, 0) -> Pids = [self()], - profile(Slogan, Fun, Pids). + {ok, TraceFile} = prepare(Slogan, Pids), + Res = (catch Fun()), + {ok, _DestFile} = analyse(Slogan), + ok = file:delete(TraceFile), + {ok, _TreeFile} = fprof_to_calltree(Slogan), + Res. -profile(Slogan, Fun, Pids) -> +%% Prepare for tracing +prepare(Slogan, Pids) -> TraceFile = lists:concat(["profile_", Slogan, "-fprof.trace"]), - DestFile = lists:concat(["profile_", Slogan, ".fprof"]), - TreeFile = lists:concat(["profile_", Slogan, ".calltree"]), - erlang:garbage_collect(), {ok, _Pid} = fprof:start(), + erlang:garbage_collect(), TraceOpts = [start, - {cpu_time, false}, - {procs, Pids}, - {file, TraceFile} + {cpu_time, false}, + {procs, Pids}, + {file, TraceFile} ], - ok = fprof:trace(TraceOpts), - Res = (catch Fun()), - ok = fprof:trace(stop), - ok = fprof:profile([{file, TraceFile}]), - ok = fprof:analyse([{dest, DestFile}]), - ok = fprof:stop(), - ok = file:delete(TraceFile), - reformat_total(DestFile, TreeFile), - Res. + ok = fprof:trace(TraceOpts), + {ok, TraceFile}. -reformat_total(FromFile, ToFile) -> - {ok, ConsultedFromFile} = file:consult(FromFile), - [_AnalysisOpts, [Totals] | Terms] = ConsultedFromFile, - {totals, _, TotalAcc, _} = Totals, +%% Stop tracing and analyse it +analyse(Slogan) -> + fprof:trace(stop), + TraceFile = lists:concat(["profile_", Slogan, "-fprof.trace"]), + DestFile = lists:concat(["profile_", Slogan, ".fprof"]), + try + case fprof:profile([{file, TraceFile}]) of + ok -> + ok = fprof:analyse([{dest, DestFile}, {totals, false}]), + {ok, DestFile}; + {error, Reason} -> + {error, Reason} + end + after + fprof:stop() + end. + +fprof_to_calltree(Slogan) -> + fprof_to_calltree(Slogan, 0). + +fprof_to_calltree(Slogan, MinPercent) -> + DestFile = lists:concat(["profile_", Slogan, ".fprof"]), + TreeFile = lists:concat(["profile_", Slogan, ".calltree"]), + fprof_to_calltree(DestFile, TreeFile, MinPercent). + +%% Create a calltree from an fprof file +fprof_to_calltree(FromFile, ToFile, MinPercent) -> + ReplyTo = self(), + Ref = make_ref(), + spawn_link(fun() -> + ReplyTo ! {Ref, do_fprof_to_calltree(FromFile, ToFile, MinPercent)} + end), + wait_for_reply(Ref). + +wait_for_reply(Ref) -> + receive + {Ref, Res} -> + Res; + {'EXIT', normal} -> + wait_for_reply(Ref); + {'EXIT', Reason} -> + exit(Reason) + end. + +do_fprof_to_calltree(FromFile, ToFile, MinPercent) -> {ok, Fd} = file:open(ToFile, [write, raw]), - Indent = "", - log(Fd, Indent, TotalAcc, Totals), - Processes = split_processes(Terms, [], []), - Reformat = fun(P) -> reformat_process(Fd, " " ++ Indent, TotalAcc, P) end, - lists:foreach(Reformat, Processes), - file:close(Fd). + {ok, ConsultedFromFile} = file:consult(FromFile), + [_AnalysisOpts, [_Totals] | Terms] = ConsultedFromFile, + Processes = split_processes(Terms, [], []), + Indent = "", + Summary = collapse_processes(Processes), + {_Label, _Cnt, Acc, _Own, _Roots, Details} = Summary, + %% log(Fd, Label, Indent, Acc, {Label, Cnt, Acc, Own}, [], 0), + gen_calltree(Fd, Indent, Acc, Summary, MinPercent), + Delim = io_lib:format("\n~80..=c\n\n", [$=]), + Write = + fun(P) -> + file:write(Fd, Delim), + gen_calltree(Fd, Indent, Acc, P, MinPercent) + end, + lists:foreach(Write, Processes), + file:write(Fd, Delim), + gen_details(Fd, Acc, Details), + file:close(Fd), + {ok, ToFile}. +%% Split all fprof terms into a list of processes split_processes([H | T], ProcAcc, TotalAcc) -> if is_tuple(H) -> @@ -75,64 +127,185 @@ split_processes([H | T], ProcAcc, TotalAcc) -> is_list(H), ProcAcc =:= [] -> split_processes(T, [H], TotalAcc); is_list(H) -> - split_processes(T, [H], [lists:reverse(ProcAcc) | TotalAcc]) + ProcAcc2 = rearrange_process(lists:reverse(ProcAcc)), + split_processes(T, [H], [ProcAcc2 | TotalAcc]) end; split_processes([], [], TotalAcc) -> - lists:reverse(TotalAcc); + lists:reverse(lists:keysort(3, TotalAcc)); split_processes([], ProcAcc, TotalAcc) -> - lists:reverse([lists:reverse(ProcAcc) | TotalAcc]). - -reformat_process(Fd, Indent, TotalAcc, Terms) -> - case Terms of - [[{ProcLabel, _, _, _}] | All] -> ok; - [[{ProcLabel,_,_,_} | _] | All] -> ok - end, - [{_, {TopKey, TopCnt, TopAcc, TopOwn}, _} | _] = All, - Process = {ProcLabel, TopCnt, TopAcc, TopOwn}, - log(Fd, Indent, TotalAcc, Process), - reformat_calls(Fd, " " ++ Indent, TotalAcc, TopKey, All, []). - -reformat_calls(Fd, Indent, TotalAcc, Key, Terms, Stack) -> - {_CalledBy, Current, Calls} = find(Key, Terms), - log(Fd, Indent, TotalAcc, Current), - case lists:member(Key, Stack) of - true -> - ok; - false -> - case Key of - {io_lib, _, _} -> - ok; - {disk_log, _, _} -> - ok; - {lists, flatten, _} -> - ok; - {lists, keysort, _} -> - ok; - _ -> - Fun = fun({NextKey, _, _, _}) -> - reformat_calls(Fd, - " " ++ Indent, - TotalAcc, - NextKey, - Terms, - [Key | Stack]) - end, - lists:foreach(Fun, Calls) - end + ProcAcc2 = rearrange_process(lists:reverse(ProcAcc)), + lists:reverse(lists:keysort(3, [ProcAcc2 | TotalAcc])). + +%% Rearrange the raw process list into a more useful format +rearrange_process([[{Label, _Cnt, _Acc, _Own} | _ ] | Details]) -> + do_rearrange_process(Details, Details, Label, [], []). + +do_rearrange_process([{CalledBy, Current, _Calls} | T], Orig, Label, Roots, Undefs) -> + case [{undefined, Cnt, safe_max(Acc, Own), Own} || + {undefined, Cnt, Acc, Own} <- CalledBy] of + [] -> + do_rearrange_process(T, Orig, Label, Roots, Undefs); + NewUndefs -> + do_rearrange_process(T, Orig, Label, [Current | Roots], NewUndefs ++ Undefs) + end; +do_rearrange_process([], Details, Label, Roots, Undefs) -> + [{undefined, Cnt, Acc, Own}] = collapse_calls(Undefs, []), + Details2 = sort_details(3, Details), + {Label, Cnt, Acc, Own, lists:reverse(lists:keysort(3, Roots)), Details2}. + +%% Compute a summary of the rearranged process info +collapse_processes(Processes) -> + Headers = lists:map(fun({_L, C, A, O, _R, _D}) -> {"SUMMARY", C, A, O} end, + Processes), + [{Label, Cnt, Acc, Own}] = collapse_calls(Headers, []), + Details = lists:flatmap(fun({_L, _C, _A, _O, _R, D}) -> D end, Processes), + Details2 = do_collapse_processes(sort_details(1, Details), []), + Roots = lists:flatmap(fun({_L, _C, _A, _O, R, _D}) -> R end, Processes), + RootMFAs = lists:usort([MFA || {MFA, _, _, _} <- Roots]), + Roots2 = [R || RootMFA <- RootMFAs, + {_, {MFA, _, _, _} = R, _} <- Details2, + MFA =:= RootMFA], + Roots3 = collapse_calls(Roots2, []), + {Label, Cnt, Acc, Own, Roots3, Details2}. + +do_collapse_processes([{CalledBy1, {MFA, Cnt1, Acc1, Own1}, Calls1} | T1], + [{CalledBy2, {MFA, Cnt2, Acc2, Own2}, Calls2} | T2]) -> + Cnt = Cnt1 + Cnt2, + Acc = Acc1 + Acc2, + Own = Own1 + Own2, + Current = {MFA, Cnt, Acc, Own}, + CalledBy0 = CalledBy1 ++ CalledBy2, + Calls0 = Calls1 ++ Calls2, + CalledBy = collapse_calls(lists:keysort(3, CalledBy0), []), + Calls = collapse_calls(lists:keysort(3, Calls0), []), + do_collapse_processes(T1, [{CalledBy, Current, Calls} | T2]); +do_collapse_processes([{CalledBy, Current, Calls} | T1], + T2) -> + do_collapse_processes(T1, [{CalledBy, Current, Calls} | T2]); +do_collapse_processes([], + T2) -> + sort_details(3, T2). + +%% Reverse sort on acc field +sort_details(Pos, Details) -> + Pivot = fun({_CalledBy1, Current1, _Calls1}, + {_CalledBy2, Current2, _Calls2}) -> + element(Pos, Current1) =< element(Pos, Current2) + end, + lists:reverse(lists:sort(Pivot, Details)). + +%% Compute a summary from a list of call tuples +collapse_calls([{MFA, Cnt1, Acc1, Own1} | T1], + [{MFA, Cnt2, Acc2, Own2} | T2]) -> + Cnt = Cnt1 + Cnt2, + Acc = safe_sum(Acc1, Acc2), + Own = Own1 + Own2, + collapse_calls(T1, [{MFA, Cnt, Acc, Own} | T2]); +collapse_calls([{MFA, Cnt, Acc, Own} | T1], + T2) -> + collapse_calls(T1, [{MFA, Cnt, Acc, Own} | T2]); +collapse_calls([], + T2) -> + lists:reverse(lists:keysort(3, T2)). + +safe_sum(Int1, Int2) -> + if + Int1 =:= undefined -> Int2; + Int2 =:= undefined -> Int1; + true -> Int1 + Int2 + end. + +safe_max(Int1, Int2) -> + if + Int1 =:= undefined -> + io:format("111\n", []), + Int2; + Int2 =:= undefined -> + io:format("222\n", []), + Int1; + Int2 > Int1 -> Int2; + true -> Int1 + end. + +%% Compute a calltree and write it to file +gen_calltree(Fd, Indent, TotalAcc, {Label, Cnt, Acc, Own, Roots, Details}, MinPercent) -> + Header = {Label, Cnt, Acc, Own}, + MetaLabel = "Process", + Diff = length(Label) - length(MetaLabel), + IoList = io_lib:format("~s~s Lvl Pct Cnt Acc Own Calls => MFA\n", + [MetaLabel, lists:duplicate(Diff, $\ )]), + file:write(Fd, IoList), + log(Fd, Label, Indent, TotalAcc, Header, Roots, MinPercent), + NewIndent = " " ++ Indent, + Fun = fun({MFA, _C, _A, _O}) -> + [put_detail(Label, D) || D <- Details], + gen_calls(Fd, Label, NewIndent, TotalAcc, MFA, MinPercent) + end, + lists:foreach(Fun, Roots). + +gen_calls(Fd, Label, Indent, TotalAcc, MFA, MinPercent) -> + case get_detail(Label, MFA) of + {read, {_CalledBy, Current, _Calls}} -> + log(Fd, Label, Indent, TotalAcc, Current, -1, MinPercent); + {unread, {_CalledBy, Current, Calls}} -> + log(Fd, Label, Indent, TotalAcc, Current, Calls, MinPercent), + NewIndent = " " ++ Indent, + Fun = fun({NextMFA, _, _, _}) -> + gen_calls(Fd, Label, NewIndent, TotalAcc, + NextMFA, MinPercent) + end, + lists:foreach(Fun, Calls) + end. + +put_detail(Label, {_, {MFA, _, _, _}, _} = Detail) -> + put({Label, MFA}, {unread, Detail}). + +get_detail(Label, MFA) -> + Val = get({Label, MFA}), + case Val of + {unread, Detail} -> + put({Label, MFA}, {read, Detail}), + Val; + {read, _Detail} -> + Val + end. + +gen_details(Fd, Total, Details) -> + IoList = io_lib:format("Pct Cnt Acc Own MFA\n", []), + file:write(Fd, IoList), + do_gen_details(Fd, Total, Details). + +do_gen_details(Fd, Total, [{_CalledBy, {MFA, Cnt, Acc, Own}, _Calls} | Details]) -> + MFAStr = io_lib:format("~p", [MFA]), + {_, Percent} = calc_percent(Acc, Own, Total), + IoList = io_lib:format("~3.. B% ~10.3B ~10.3f ~10.3f => ~s\n", + [Percent, Cnt, Acc, Own, MFAStr]), + file:write(Fd, IoList), + do_gen_details(Fd, Total, Details); +do_gen_details(_Fd, _Total, []) -> + ok. + +log(Fd, Label, Indent, Acc, Current, Calls, MinPercent) when is_list(Calls) -> + log(Fd, Label, Indent, Acc, Current, length(Calls), MinPercent); +log(Fd, Label, Indent, Total, {MFA, Cnt, Acc, Own}, N, MinPercent) -> + {Max, Percent} = calc_percent(Acc, Own, Total), + if + Percent >= MinPercent -> + do_log(Fd, Label, Indent, Percent, MFA, Cnt, Max, Own, N); + true -> + ok end. -find(Key, [{_, {Key, _, _, _}, _} = H | _]) -> - H; -find(Key, [{_, {_, _, _, _}, _} | T]) -> - find(Key, T). - -log(Fd, Indent, Total, {Label, Cnt, Acc, Own}) -> - Percent = case Acc of - undefined -> 100; - _ -> trunc((lists:max([Acc, Own]) * 100) / Total) - end, - Label2 = io_lib:format("~p", [Label]), - IoList = io_lib:format("~s~p% ~s \t~p \t~p \t~p\n", - [Indent, Percent, Label2, Cnt, trunc(Acc), trunc(Own)]), +do_log(Fd, Label, Indent, Percent, MFA, Cnt, Acc, Own, N) -> + MFAStr = io_lib:format("~p", [MFA]), + CallsStr = io_lib:format(" ~5.. s ", [lists:concat([N])]), + IoList = io_lib:format("~s ~3.. B " + "~s~3.. B% ~10.. B ~10.. B ~10.. B ~s => ~s\n", + [Label, length(Indent) div 2, + Indent, Percent, Cnt, + round(Acc), round(Own), CallsStr, MFAStr]), file:write(Fd, IoList). +calc_percent(Acc, Own, Total) -> + Max = safe_max(Acc, Own), + {Max, round((Max * 100) / Total)}. diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl index 41f6c2c4cb..282fd91b44 100644 --- a/lib/megaco/test/megaco_test_lib.erl +++ b/lib/megaco/test/megaco_test_lib.erl @@ -21,6 +21,7 @@ %%---------------------------------------------------------------------- %% Purpose: Lightweight test server %%---------------------------------------------------------------------- +%% -module(megaco_test_lib). @@ -684,7 +685,7 @@ skip(Actual, File, Line) -> fatal_skip(Actual, File, Line) -> error(Actual, File, Line), - exit(shutdown). + exit({skipped, {fatal, Actual, File, Line}}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -749,6 +750,7 @@ proxy_loop(OwnId, Controller) -> proxy_loop(OwnId, Controller) end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Test server callbacks init_per_testcase(_Case, Config) -> @@ -852,10 +854,10 @@ watchdog(Pid, Time) -> prepare_test_case(Actions, N, Config, File, Line) -> OrigNodes = lookup_config(nodes, Config), TestNodes = lookup_config(nodenames, Config), %% For testserver - This = node(), + This = node(), SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes), - AllNodes = [This | (SomeNodes -- [This])], - Nodes = pick_n_nodes(N, AllNodes, File, Line), + AllNodes = [This | (SomeNodes -- [This])], + Nodes = pick_n_nodes(N, AllNodes, File, Line), start_nodes(Nodes, File, Line), do_prepare_test_case(Actions, Nodes, Config, File, Line). diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index c1476488ca..35acffcb64 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = megaco -MEGACO_VSN = 3.15.1.1 +MEGACO_VSN = 3.15.1.2 PRE_VSN = APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile index f45b5137a3..f2e581f9d3 100644 --- a/lib/mnesia/doc/src/Makefile +++ b/lib/mnesia/doc/src/Makefile @@ -29,14 +29,6 @@ VSN=$(MNESIA_VSN) APPLICATION=mnesia # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -105,31 +97,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -142,8 +113,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -158,33 +127,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -199,8 +141,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -211,30 +151,4 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif - - release_spec: - diff --git a/lib/mnesia/doc/src/make.dep b/lib/mnesia/doc/src/make.dep deleted file mode 100644 index 6e79484cb3..0000000000 --- a/lib/mnesia/doc/src/make.dep +++ /dev/null @@ -1,46 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: Mnesia_App_A.tex Mnesia_App_B.tex Mnesia_App_C.tex \ - Mnesia_App_D.tex Mnesia_chap1.tex Mnesia_chap2.tex \ - Mnesia_chap3.tex Mnesia_chap4.tex Mnesia_chap5.tex \ - Mnesia_chap7.tex Mnesia_chap8.tex book.tex \ - mnesia.tex mnesia_frag_hash.tex mnesia_registry.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -Mnesia_App_B.tex: ../../src/mnesia_backup.erl - -Mnesia_App_C.tex: ../../src/mnesia_frag.erl - -Mnesia_App_D.tex: ../../src/mnesia_frag_hash.erl - -Mnesia_chap2.tex: company.erl company.hrl - -Mnesia_chap3.tex: company.erl - -Mnesia_chap4.tex: company.erl - -Mnesia_chap5.tex: FRUITS company.erl company_o.erl company_o.hrl - -Mnesia_chap7.tex: bup.erl - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: company.ps - diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 8ef573a948..1bb80f8fe3 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -38,7 +38,35 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.5</title> + <section><title>Mnesia 4.5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix deadlock in mnesia:del_table_copy/2.</p> + <p> + Own Id: OTP-9689 Aux Id: seq11927 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Allow schema operations when using different mnesia + versions.</p> + <p> + Own Id: OTP-9657 Aux Id: seq11926 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.5</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src index fe4e5e2e7a..e0954ad206 100644 --- a/lib/mnesia/src/mnesia.appup.src +++ b/lib/mnesia/src/mnesia.appup.src @@ -1,12 +1,14 @@ %% -*- erlang -*- -{"%VSN%", +{"%VSN%", [ + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, {"4.4.16", [{restart_application, mnesia}]} ], [ + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 47dcdad7ac..14414537b9 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -372,7 +372,9 @@ mk_str() -> lists:concat([node()] ++ Now ++ ".TMP"). make_initial_backup(Ns, Opaque, Mod) -> - Schema = [{schema, schema, mnesia_schema:get_initial_schema(disc_copies, Ns)}], + Orig = mnesia_schema:get_initial_schema(disc_copies, Ns), + Modded = proplists:delete(storage_properties, proplists:delete(majority, Orig)), + Schema = [{schema, schema, Modded}], O2 = do_apply(Mod, open_write, [Opaque], Opaque), O3 = do_apply(Mod, write, [O2, [mnesia_log:backup_log_header()]], O2), O4 = do_apply(Mod, write, [O3, Schema], O3), diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 1d3bd55b48..6a561394d5 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -289,40 +289,7 @@ get_remote_cstructs() -> get_cstructs() -> {cstructs, Cstructs, Running} = call(get_cstructs), Node = node(group_leader()), - {cstructs, normalize_cstructs(Cstructs, Node), Running}. - -normalize_cstructs(Cstructs, Node) -> - %% backward-compatibility hack; normalize before returning - case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of - {badrpc, _} -> - %% assume it's not a schema merge - Cstructs; - #cstruct{} -> - %% same format - Cstructs; - Cstruct -> - %% some other format - RemoteFields = [F || {F,_} <- rpc:call(Node, mnesia_schema, cs2list, [Cstruct])], - [convert_cs(Cs, RemoteFields) || Cs <- Cstructs] - end. - -convert_cs(Cs, Fields) -> - MyFields = record_info(fields, cstruct), - convert(tl(tuple_to_list(Cs)), MyFields, Fields, []). - -convert([H|T], [F|FsL], [F|FsR], Acc) -> - convert(T, FsL, FsR, [H|Acc]); -convert([H|T], [Fl|FsL] = L, [Fr|FsR] = R, Acc) -> - case {lists:member(Fl, FsR), lists:member(Fr, FsL)} of - {true, false} -> - convert(T, L, FsR, [H|Acc]); - {false, true} -> - %% Field Fl doesn't exist on receiver side; skip. - convert(T, FsL, R, Acc) - end; -convert([], _, _, Acc) -> - list_to_tuple([cstruct|lists:reverse(Acc)]). - + {cstructs, mnesia_schema:normalize_cs(Cstructs, Node), Running}. update(Fun) -> call({update,Fun}). diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl index ec6b99ecaa..5a060a28ff 100644 --- a/lib/mnesia/src/mnesia_event.erl +++ b/lib/mnesia/src/mnesia_event.erl @@ -121,7 +121,7 @@ handle_system_event({mnesia_up, Node}, State) -> {ok, State#state{nodes = Nodes}}; handle_system_event({mnesia_down, Node}, State) -> - case mnesia:system_info(fallback_activated) of + case mnesia:system_info(fallback_activated) andalso Node =/= node() of true -> case mnesia_monitor:get_env(fallback_error_function) of {mnesia, lkill} -> @@ -129,8 +129,8 @@ handle_system_event({mnesia_down, Node}, State) -> "must be restarted. Forcing shutdown " "after mnesia_down from ~p...~n", report_fatal(Msg, [Node], nocore, State#state.dumped_core), - mnesia:lkill(), - exit(fatal); + catch exit(whereis(mnesia_monitor), fatal), + {ok, State}; {UserMod, UserFunc} -> Msg = "Warning: A fallback is installed and Mnesia got mnesia_down " "from ~p. ~n", diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index 9e77fe0b9f..4a1616e054 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -758,7 +758,7 @@ make_activate(Tab, Props) -> [] -> Cs2 = Cs#cstruct{frag_properties = Props}, [Cs3] = expand_cstruct(Cs2, activate), - TabDef = mnesia_schema:cs2list(Cs3), + TabDef = mnesia_schema:vsn_cs2list(Cs3), Op = {op, change_table_frag, activate, TabDef}, [[Op]]; BadProps -> @@ -783,7 +783,7 @@ make_deactivate(Tab) -> mnesia:abort({combine_error, Tab, "Too many fragments"}); true -> Cs2 = Cs#cstruct{frag_properties = []}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, deactivate, TabDef}, [[Op]] end. @@ -850,7 +850,7 @@ make_add_frag(Tab, SortedNs) -> SplitOps = split(Tab, FH2, FromIndecies, FragNames, []), Cs2 = replace_frag_hash(Cs, FH2), - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), BaseOp = {op, change_table_frag, {add_frag, SortedNs}, TabDef}, [BaseOp, NewOp | SplitOps]. @@ -962,7 +962,7 @@ make_del_frag(Tab) -> LastFrag = element(N, FragNames), [LastOp] = mnesia_schema:make_delete_table(LastFrag, single_frag), Cs2 = replace_frag_hash(Cs, FH2), - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), BaseOp = {op, change_table_frag, del_frag, TabDef}, [BaseOp, LastOp | MergeOps]; _ -> @@ -1075,7 +1075,7 @@ make_add_node(Tab, Node) when is_atom(Node) -> Props = Cs#cstruct.frag_properties, Props2 = lists:keyreplace(node_pool, 1, Props, {node_pool, Pool2}), Cs2 = Cs#cstruct{frag_properties = Props2}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, {add_node, Node}, TabDef}, [Op]; true -> @@ -1104,7 +1104,7 @@ make_del_node(Tab, Node) when is_atom(Node) -> Pool2 = Pool -- [Node], Props = lists:keyreplace(node_pool, 1, Cs#cstruct.frag_properties, {node_pool, Pool2}), Cs2 = Cs#cstruct{frag_properties = Props}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, {del_node, Node}, TabDef}, [Op]; false -> diff --git a/lib/mnesia/src/mnesia_frag_hash.erl b/lib/mnesia/src/mnesia_frag_hash.erl index 610ba2535c..d70579c3b3 100644 --- a/lib/mnesia/src/mnesia_frag_hash.erl +++ b/lib/mnesia/src/mnesia_frag_hash.erl @@ -101,21 +101,19 @@ del_frag(OldState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) -> - P = SplitN, - A = erlang:phash(Key, power2(L)), +key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash(Key, power2(L + 1)), if - A < P -> - erlang:phash(Key, power2(L + 1)); + A > N -> + A - power2(L); true -> A end; -key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) -> - P = SplitN, - A = erlang:phash2(Key, power2(L)) + 1, +key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash2(Key, power2(L + 1)) + 1, if - A < P -> - erlang:phash2(Key, power2(L + 1)) + 1; + A > N -> + A - power2(L); true -> A end; diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index e110ad3241..8cb2e92c08 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -536,7 +536,11 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() -> dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]), - exit(State#state.supervisor, shutdown), + %% This may hang supervisor if a shutdown happens at the same time as an fatal + %% is in progress + %% exit(State#state.supervisor, shutdown), + %% It is better to kill an innocent process + catch exit(whereis(mnesia_locker), kill), {noreply, State}; handle_info(Msg = {'EXIT',Pid,_}, State) -> diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 05be474aea..179e15197e 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -39,9 +39,10 @@ change_table_load_order/2, change_table_majority/2, change_table_frag/2, - clear_table/1, +%% clear_table/1, %% removed since it is not a schema op anymore create_table/1, cs2list/1, + vsn_cs2list/1, del_snmp/1, del_table_copy/2, del_table_index/2, @@ -65,6 +66,7 @@ merge_schema/0, merge_schema/1, move_table/3, + normalize_cs/2, opt_create_dir/2, prepare_commit/3, purge_dir/2, @@ -626,6 +628,17 @@ do_insert_schema_ops(Store, [Head | Tail]) -> do_insert_schema_ops(_Store, []) -> ok. +api_list2cs(List) when is_list(List) -> + Name = pick(unknown, name, List, must), + Keys = check_keys(Name, List, record_info(fields, cstruct)), + check_duplicates(Name, Keys), + list2cs(List); +api_list2cs(Other) -> + mnesia:abort({badarg, Other}). + +vsn_cs2list(Cs) -> + cs2list(need_old_cstructs(), Cs). + cs2list(Cs) when is_record(Cs, cstruct) -> Tags = record_info(fields, cstruct), rec2list(Tags, Tags, 2, Cs); @@ -648,7 +661,7 @@ cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> cs2list(false, Cs) -> cs2list(Cs); -cs2list(ver4_4_18, Cs) -> +cs2list(ver4_4_18, Cs) -> %% Or earlier Orig = record_info(fields, cstruct), Tags = [name,type,ram_copies,disc_copies,disc_only_copies, load_order,access_mode,index,snmp,local_content, @@ -671,13 +684,19 @@ rec2list([], _, _Pos, _Rec) -> rec2list(Tags, [_|Orig], Pos, Rec) -> rec2list(Tags, Orig, Pos+1, Rec). -api_list2cs(List) when is_list(List) -> - Name = pick(unknown, name, List, must), - Keys = check_keys(Name, List, record_info(fields, cstruct)), - check_duplicates(Name, Keys), - list2cs(List); -api_list2cs(Other) -> - mnesia:abort({badarg, Other}). +normalize_cs(Cstructs, Node) -> + %% backward-compatibility hack; normalize before returning + case need_old_cstructs([Node]) of + false -> + Cstructs; + Version -> + %% some other format + [convert_cs(Version, Cs) || Cs <- Cstructs] + end. + +convert_cs(Version, Cs) -> + Fields = [Value || {_, Value} <- cs2list(Version, Cs)], + list_to_tuple([cstruct|Fields]). list2cs(List) when is_list(List) -> Name = pick(unknown, name, List, must), @@ -1048,7 +1067,7 @@ unsafe_make_create_table(Cs) -> Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(Cs), RunningNodes), Store = Ts#tidstore.store, mnesia_locker:wlock_no_exist(Tid, Store, Tab, Nodes), - [{op, create_table, cs2list(Cs)}]. + [{op, create_table, vsn_cs2list(Cs)}]. check_if_exists(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), @@ -1133,7 +1152,7 @@ make_delete_table2(Tab) -> Cs = val({Tab, cstruct}), ensure_active(Cs), ensure_writable(Tab), - {op, delete_table, cs2list(Cs)}. + {op, delete_table, vsn_cs2list(Cs)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Change fragmentation of a table @@ -1152,10 +1171,6 @@ do_change_table_frag(Tab, _Change) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Clear a table -%% No need for a schema transaction -clear_table(Tab) -> - schema_transaction(fun() -> do_clear_table(Tab) end). - do_clear_table(schema) -> mnesia:abort({bad_type, schema}); do_clear_table(Tab) -> @@ -1166,7 +1181,7 @@ do_clear_table(Tab) -> make_clear_table(Tab) -> Cs = val({Tab, cstruct}), ensure_writable(Tab), - [{op, clear_table, cs2list(Cs)}]. + [{op, clear_table, vsn_cs2list(Cs)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1206,7 +1221,7 @@ make_add_table_copy(Tab, Node, Storage) -> IsRunning == false -> mnesia:abort({not_active, schema, Node}) end, - [{op, add_table_copy, Storage, Node, cs2list(Cs2)}]. + [{op, add_table_copy, Storage, Node, vsn_cs2list(Cs2)}]. del_table_copy(Tab, Node) -> schema_transaction(fun() -> do_del_table_copy(Tab, Node) end). @@ -1235,11 +1250,11 @@ make_del_table_copy(Tab, Node) -> ensure_not_active(Tab, Node), verify_cstruct(Cs2), Ops = remove_node_from_tabs(val({schema, tables}), Node), - [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)} | Ops]; + [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)} | Ops]; _ -> ensure_active(Cs), verify_cstruct(Cs2), - [{op, del_table_copy, Storage, Node, cs2list(Cs2)}] + [{op, del_table_copy, Storage, Node, vsn_cs2list(Cs2)}] end. remove_node_from_tabs([], _Node) -> @@ -1253,7 +1268,7 @@ remove_node_from_tabs([Tab|Rest], Node) -> unknown -> case IsFragModified of true -> - [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} | + [{op, change_table_frag, {del_node, Node}, vsn_cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; false -> remove_node_from_tabs(Rest, Node) @@ -1262,11 +1277,11 @@ remove_node_from_tabs([Tab|Rest], Node) -> Cs2 = new_cs(Cs, Node, Storage, del), case mnesia_lib:cs_to_nodes(Cs2) of [] -> - [{op, delete_table, cs2list(Cs)} | + [{op, delete_table, vsn_cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; _Ns -> verify_cstruct(Cs2), - [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)}| + [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)}| remove_node_from_tabs(Rest, Node)] end end. @@ -1318,9 +1333,9 @@ make_move_table(Tab, FromNode, ToNode) -> Cs2 = new_cs(Cs, ToNode, Storage, add), Cs3 = new_cs(Cs2, FromNode, Storage, del), verify_cstruct(Cs3), - [{op, add_table_copy, Storage, ToNode, cs2list(Cs2)}, + [{op, add_table_copy, Storage, ToNode, vsn_cs2list(Cs2)}, {op, sync_trans}, - {op, del_table_copy, Storage, FromNode, cs2list(Cs3)}]. + {op, del_table_copy, Storage, FromNode, vsn_cs2list(Cs3)}]. %% end of functions to add and delete nodes to tables %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1357,7 +1372,7 @@ make_change_table_copy_type(Tab, Node, ToS) -> Cs3 = new_cs(Cs2, Node, ToS, add), verify_cstruct(Cs3), - [{op, change_table_copy_type, Node, FromS, ToS, cs2list(Cs3)}]. + [{op, change_table_copy_type, Node, FromS, ToS, vsn_cs2list(Cs3)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% change index functions .... @@ -1383,7 +1398,7 @@ make_add_table_index(Tab, Pos) -> Ix2 = lists:sort([Pos | Ix]), Cs2 = Cs#cstruct{index = Ix2}, verify_cstruct(Cs2), - [{op, add_index, Pos, cs2list(Cs2)}]. + [{op, add_index, Pos, vsn_cs2list(Cs2)}]. del_table_index(Tab, Pos) -> schema_transaction(fun() -> do_del_table_index(Tab, Pos) end). @@ -1404,7 +1419,7 @@ make_del_table_index(Tab, Pos) -> verify(true, lists:member(Pos, Ix), {no_exists, Tab, Pos}), Cs2 = Cs#cstruct{index = lists:delete(Pos, Ix)}, verify_cstruct(Cs2), - [{op, del_index, Pos, cs2list(Cs2)}]. + [{op, del_index, Pos, vsn_cs2list(Cs2)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1427,7 +1442,7 @@ make_add_snmp(Tab, Ustruct) -> verify(true, mnesia_snmp_hook:check_ustruct(Ustruct), Error), Cs2 = Cs#cstruct{snmp = Ustruct}, verify_cstruct(Cs2), - [{op, add_snmp, Ustruct, cs2list(Cs2)}]. + [{op, add_snmp, Ustruct, vsn_cs2list(Cs2)}]. del_snmp(Tab) -> schema_transaction(fun() -> do_del_snmp(Tab) end). @@ -1445,7 +1460,7 @@ make_del_snmp(Tab) -> ensure_active(Cs), Cs2 = Cs#cstruct{snmp = []}, verify_cstruct(Cs2), - [{op, del_snmp, cs2list(Cs2)}]. + [{op, del_snmp, vsn_cs2list(Cs2)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -1477,26 +1492,26 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) -> [] -> Cs2 = Cs#cstruct{attributes = NewAttrs, record_name = NewRecName}, verify_cstruct(Cs2), - [{op, transform, Fun, cs2list(Cs2)}]; + [{op, transform, Fun, vsn_cs2list(Cs2)}]; PosList -> DelIdx = fun(Pos, Ncs) -> Ix = Ncs#cstruct.index, Ncs1 = Ncs#cstruct{index = lists:delete(Pos, Ix)}, - Op = {op, del_index, Pos, cs2list(Ncs1)}, + Op = {op, del_index, Pos, vsn_cs2list(Ncs1)}, {Op, Ncs1} end, AddIdx = fun(Pos, Ncs) -> Ix = Ncs#cstruct.index, Ix2 = lists:sort([Pos | Ix]), Ncs1 = Ncs#cstruct{index = Ix2}, - Op = {op, add_index, Pos, cs2list(Ncs1)}, + Op = {op, add_index, Pos, vsn_cs2list(Ncs1)}, {Op, Ncs1} end, {DelOps, Cs1} = lists:mapfoldl(DelIdx, Cs, PosList), Cs2 = Cs1#cstruct{attributes = NewAttrs, record_name = NewRecName}, {AddOps, Cs3} = lists:mapfoldl(AddIdx, Cs2, PosList), verify_cstruct(Cs3), - lists:flatten([DelOps, {op, transform, Fun, cs2list(Cs2)}, AddOps]) + lists:flatten([DelOps, {op, transform, Fun, vsn_cs2list(Cs2)}, AddOps]) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1520,7 +1535,7 @@ make_change_table_access_mode(Tab, Mode) -> verify(false, OldMode == Mode, {already_exists, Tab, Mode}), Cs2 = Cs#cstruct{access_mode = Mode}, verify_cstruct(Cs2), - [{op, change_table_access_mode, cs2list(Cs2), OldMode, Mode}]. + [{op, change_table_access_mode, vsn_cs2list(Cs2), OldMode, Mode}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1541,7 +1556,7 @@ make_change_table_load_order(Tab, LoadOrder) -> OldLoadOrder = Cs#cstruct.load_order, Cs2 = Cs#cstruct{load_order = LoadOrder}, verify_cstruct(Cs2), - [{op, change_table_load_order, cs2list(Cs2), OldLoadOrder, LoadOrder}]. + [{op, change_table_load_order, vsn_cs2list(Cs2), OldLoadOrder, LoadOrder}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1571,14 +1586,14 @@ make_change_table_majority(Tab, Majority) -> ensure_active(CsT), CsT2 = CsT#cstruct{majority = Majority}, verify_cstruct(CsT2), - {op, change_table_majority, cs2list(CsT2), + {op, change_table_majority, vsn_cs2list(CsT2), OldMajority, Majority} end, FragNames); false -> []; {_, _} -> mnesia:abort({bad_type, Tab}) end, verify_cstruct(Cs2), - [{op, change_table_majority, cs2list(Cs2), OldMajority, Majority} | FragOps]. + [{op, change_table_majority, vsn_cs2list(Cs2), OldMajority, Majority} | FragOps]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1619,7 +1634,7 @@ make_write_table_properties(Tab, [Prop | Props], Cs) -> MergedProps = lists:merge(DelProps, [Prop]), Cs2 = Cs#cstruct{user_properties = MergedProps}, verify_cstruct(Cs2), - [{op, write_property, cs2list(Cs2), Prop} | + [{op, write_property, vsn_cs2list(Cs2), Prop} | make_write_table_properties(Tab, Props, Cs2)]; make_write_table_properties(_Tab, [], _Cs) -> []. @@ -1740,7 +1755,7 @@ make_delete_table_properties(Tab, [PropKey | PropKeys], Cs) -> Props = lists:keydelete(PropKey, 1, OldProps), Cs2 = Cs#cstruct{user_properties = Props}, verify_cstruct(Cs2), - [{op, delete_property, cs2list(Cs2), PropKey} | + [{op, delete_property, vsn_cs2list(Cs2), PropKey} | make_delete_table_properties(Tab, PropKeys, Cs2)]; make_delete_table_properties(_Tab, [], _Cs) -> []. @@ -2166,12 +2181,17 @@ receive_sync(Nodes, Pids) -> {abort, Else} end. -lock_del_table(Tab, Node, Cs, Father) -> +lock_del_table(Tab, NewNode, Cs0, Father) -> Ns = val({schema, active_replicas}), process_flag(trap_exit,true), Lock = fun() -> mnesia:write_lock_table(Tab), - {Res, []} = rpc:multicall(Ns, ?MODULE, set_where_to_read, [Tab, Node, Cs]), + %% Sigh using cs record + Set = fun(Node) -> + [Cs] = normalize_cs([Cs0], Node), + rpc:call(Node, ?MODULE, set_where_to_read, [Tab, NewNode, Cs]) + end, + Res = [Set(Node) || Node <- Ns], Filter = fun(ok) -> false; ({badrpc, {'EXIT', {undef, _}}}) -> @@ -2353,11 +2373,12 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) -> undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) when Node == node() -> + WriteLocker = get(mnesia_lock), + WriteLocker =/= undefined andalso (WriteLocker ! die), Cs = list2cs(TabDef), Tab = Cs#cstruct.name, mnesia_lib:set({Tab, where_to_read}, Node); - undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}) when N == node() -> Cs = list2cs(TabDef), @@ -2829,6 +2850,9 @@ fetch_cstructs(Node) -> rpc:call(Node, mnesia_controller, get_remote_cstructs, []) end. +need_old_cstructs() -> + need_old_cstructs(val({schema, where_to_write})). + need_old_cstructs(Nodes) -> Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end, case lists:dropwhile(Filter, Nodes) of diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl index 63f4146d98..9e0a8db1ae 100644 --- a/lib/mnesia/test/mnesia_evil_backup.erl +++ b/lib/mnesia/test/mnesia_evil_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -244,9 +244,9 @@ restore(Config, Op) -> [rpc:call(Node, ?MODULE, check_tab, [Res31, ?LINE]) || Node <- Nodes], %% Restore all tables on it's nodes - mnesia_schema:clear_table(Tab1), - mnesia_schema:clear_table(Tab2), - mnesia_schema:clear_table(Tab3), + mnesia:clear_table(Tab1), + mnesia:clear_table(Tab2), + mnesia:clear_table(Tab3), [mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)], diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 668eba176f..17d6c6c212 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1795,7 +1795,7 @@ subscribe_extended(Config) when is_list(Config) -> ?match({mnesia_table_event, {delete, schema, {schema, Tab1}, [{schema, Tab1, _}],_}}, recv_event()), ?match({mnesia_table_event, {write, schema, {schema, Tab1, _}, [], _}}, recv_event()), - ?match({atomic, ok}, mnesia_schema:clear_table(Tab2)), + ?match({atomic, ok}, mnesia:clear_table(Tab2)), ?match({mnesia_table_event, {delete, schema, {schema, Tab2}, [{schema, Tab2, _}],_}}, recv_event()), ?match({mnesia_table_event, {write, schema, {schema, Tab2, _}, [], _}}, recv_event()), diff --git a/lib/mnesia/test/mnesia_frag_hash_test.erl b/lib/mnesia/test/mnesia_frag_hash_test.erl new file mode 100644 index 0000000000..095d25e74f --- /dev/null +++ b/lib/mnesia/test/mnesia_frag_hash_test.erl @@ -0,0 +1,94 @@ +-module(mnesia_frag_hash_test). + +-export([test/0]). + +-define(NUM_FRAGS, 20). +-define(NUM_KEYS, 10000). + +-record(hash_state, + {n_fragments, + next_n_to_split, + n_doubles, + function}). + +% OLD mnesia_frag_hash:key_to_frag_number/2. +old_key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) -> + P = SplitN, + A = erlang:phash(Key, power2(L)), + if + A < P -> + erlang:phash(Key, power2(L + 1)); + true -> + A + end; +old_key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) -> + P = SplitN, + A = erlang:phash2(Key, power2(L)) + 1, + if + A < P -> + erlang:phash2(Key, power2(L + 1)) + 1; + true -> + A + end; +old_key_to_frag_number(OldState, Key) -> + State = convert_old_state(OldState), + old_key_to_frag_number(State, Key). + + +% NEW mnesia_frag_hash:key_to_frag_number/2. +new_key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash(Key, power2(L + 1)), + if + A > N -> + A - power2(L); + true -> + A + end; +new_key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash2(Key, power2(L + 1)) + 1, + if + A > N -> + A - power2(L); + true -> + A + end; +new_key_to_frag_number(OldState, Key) -> + State = convert_old_state(OldState), + new_key_to_frag_number(State, Key). + + +% Helpers for key_to_frag_number functions. + +power2(Y) -> + 1 bsl Y. % trunc(math:pow(2, Y)). + +convert_old_state({hash_state, N, P, L}) -> + #hash_state{n_fragments = N, + next_n_to_split = P, + n_doubles = L, + function = phash}. + + +test() -> + test2(mnesia_frag_hash:init_state(undefined, undefined)), % phash2 + test2({hash_state, 1, 1, 0}). % phash + +test2(I) -> + test_keys(I), + lists:foldl( + fun(_, S) -> test_frag(S) end, + I, lists:seq(1, ?NUM_FRAGS)), + ok. + +test_frag(State) -> + {State2,_,_} = mnesia_frag_hash:add_frag(State), + test_keys(State2), + State2. + +test_keys(State) -> + [test_key(State, Key) || Key <- lists:seq(1, ?NUM_KEYS)]. + +test_key(State, Key) -> + Old = old_key_to_frag_number(State, Key), + New = new_key_to_frag_number(State, Key), + Old = New. diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl index 5d55fcac0e..3a2d44aa95 100644 --- a/lib/mnesia/test/mnesia_install_test.erl +++ b/lib/mnesia/test/mnesia_install_test.erl @@ -205,7 +205,7 @@ silly_upgrade(Config) when is_list(Config) -> ?match(ok, mnesia:install_fallback(Bup2)), file:delete(Bup2), %% Will generate intentional crash, fatal error - ?match([], mnesia_test_lib:stop_mnesia([Node2])), + ?match([], mnesia_test_lib:stop_mnesia([Node2])), wait_till_dead([Node1, Node2]), ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), ?match(match, verify_state(Tab1, Tab2, CpState)), @@ -213,22 +213,29 @@ silly_upgrade(Config) when is_list(Config) -> ?match(ok, mnesia:install_fallback(Bup)), file:delete(Bup), %% Will generate intentional crash, fatal error - ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])), + ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])), wait_till_dead([Node1, Node2]), ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), CpState2 = [X || X <- CpState, element(1, X) /= Tab1], ?match(match, verify_state(Tab1, Tab2, CpState2)), ?verify_mnesia(Nodes, []). -wait_till_dead([]) -> ok; -wait_till_dead([N|Ns]) -> +wait_till_dead([]) -> + ok; %% timer:sleep(5); +wait_till_dead(Repeat = [N|Ns]) -> Apps = rpc:call(N, application, which_applications, []), case lists:keymember(mnesia, 1, Apps) of - true -> + true -> timer:sleep(10), - wait_till_dead([N|Ns]); - false -> - wait_till_dead(Ns) + wait_till_dead(Repeat); + false -> + case rpc:call(N, erlang, whereis, [mnesia_monitor]) of + undefined -> + wait_till_dead(Ns); + _ -> + timer:sleep(10), + wait_till_dead(Repeat) + end end. add_some_records(Tab1, Tab2, Old) -> diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index a21ab007ef..ebf79dd2ae 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.5 +MNESIA_VSN = 4.5.1 diff --git a/lib/observer/doc/src/make.dep b/lib/observer/doc/src/make.dep deleted file mode 100644 index 3c1b3df771..0000000000 --- a/lib/observer/doc/src/make.dep +++ /dev/null @@ -1,29 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex crashdump.tex crashdump_ug.tex etop.tex \ - etop_ug.tex observer_app.tex part.tex ref_man.tex \ - ttb.tex ttb_ug.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: etop_5.ps etop_lines.ps etop_main.ps etop_opt.ps - -book.dvi: et_modsprocs.ps et_processes.ps - diff --git a/lib/observer/priv/erlang_observer.png b/lib/observer/priv/erlang_observer.png Binary files differnew file mode 100644 index 0000000000..78e70461b1 --- /dev/null +++ b/lib/observer/priv/erlang_observer.png diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile index 3875b62101..95954d8587 100644 --- a/lib/observer/src/Makefile +++ b/lib/observer/src/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# +# # Copyright Ericsson AB 2002-2011. All Rights Reserved. -# +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # 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 online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # include $(ERL_TOP)/make/target.mk @@ -41,8 +41,19 @@ MODULES= \ etop_gui \ etop_tr \ etop_txt \ + observer \ + observer_lib \ + observer_wx \ + observer_pro_wx \ + observer_procinfo \ + observer_sys_wx \ + observer_trace_wx \ + observer_traceoptions_wx \ + observer_tv_table \ + observer_tv_wx \ ttb \ ttb_et + HRL_FILES= \ ../include/etop.hrl INTERNAL_HRL_FILES= \ @@ -54,7 +65,7 @@ EXAMPLE_FILES= multitrace.erl TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) PRIVDIR= ../priv -WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool +WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool $(PRIVDIR)/erlang_observer.png BINDIR= $(PRIVDIR)/bin ifeq ($(findstring win32,$(TARGET)),win32) WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/getop.bat $(BINDIR)/cdv.bat @@ -109,7 +120,7 @@ docs: # ---------------------------------------------------- # Release Target -# ---------------------------------------------------- +# ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt diff --git a/lib/observer/src/observer.erl b/lib/observer/src/observer.erl new file mode 100644 index 0000000000..098100e8ee --- /dev/null +++ b/lib/observer/src/observer.erl @@ -0,0 +1,25 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer). + +-export([start/0]). + + +start() -> + observer_wx:start(). diff --git a/lib/observer/src/observer_defs.hrl b/lib/observer/src/observer_defs.hrl new file mode 100644 index 0000000000..d83a1e2fa5 --- /dev/null +++ b/lib/observer/src/observer_defs.hrl @@ -0,0 +1,62 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-record(trace_options, {send = false, + treceive = false, + functions = false, + events = false, + on_1st_spawn = false, + on_all_spawn = false, + on_1st_link = false, + on_all_link = false, + main_window = true}). + +-record(match_spec, {name = "", + term = [], + str = [], + func = ""}). + +-record(tpattern, {m, fa, ms}). + +-record(traced_func, {func_name, %atom + arity, %integer + match_spec = #match_spec{}}). + +-record(on_spawn, {checkbox, all_spawn, first_spawn}). + +-record(on_link, {checkbox, all_link, first_link}). + +-record(pid, {window, traced}). + +-record(create_menu, + {id, + text, + type = append, + check = false + }). + +-record(attrs, {even, odd, deleted, changed, searched}). +-define(EVEN(Row), ((Row rem 2) =:= 0)). +-define(BG_EVEN, {230,230,250}). +-define(BG_ODD, {255,255,255}). +-define(BG_DELETED, {100,100,100}). +-define(FG_DELETED, {240,30,30}). +-define(BG_SEARCHED,{235,215,90}). +-define(BG_CHANGED, {230,230,250}). + +-define(LCTRL_WDECR, 4). %% Remove some pixels in column width to avoid creating unnecessary scrollbar diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl new file mode 100644 index 0000000000..90c270e977 --- /dev/null +++ b/lib/observer/src/observer_lib.erl @@ -0,0 +1,297 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer_lib). + +-export([get_wx_parent/1, + display_info_dialog/1, + interval_dialog/4, start_timer/1, stop_timer/1, + display_info/2, fill_info/2, update_info/2, to_str/1, + create_menus/3, create_menu_item/3, + create_attrs/0 + ]). + +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). + +get_wx_parent(Window) -> + Parent = wxWindow:getParent(Window), + case wx:is_null(Parent) of + true -> Window; + false -> get_wx_parent(Parent) + end. + +interval_dialog(Parent0, {Timer, Value}, Min, Max) -> + Parent = get_wx_parent(Parent0), + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Update Interval", + [{style, ?wxDEFAULT_DIALOG_STYLE bor + ?wxRESIZE_BORDER}]), + Panel = wxPanel:new(Dialog), + Check = wxCheckBox:new(Panel, ?wxID_ANY, "Periodical refresh"), + wxCheckBox:setValue(Check, Timer /= false), + Style = ?wxSL_HORIZONTAL bor ?wxSL_AUTOTICKS bor ?wxSL_LABELS, + Slider = wxSlider:new(Panel, ?wxID_ANY, Value, Min, Max, + [{style, Style}, {size, {200, -1}}]), + wxWindow:enable(Slider, [{enable, Timer /= false}]), + InnerSizer = wxBoxSizer:new(?wxVERTICAL), + Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + Flags = [{flag, ?wxEXPAND bor ?wxALL}, {border, 2}], + wxSizer:add(InnerSizer, Check, Flags), + wxSizer:add(InnerSizer, Slider, Flags), + wxPanel:setSizer(Panel, InnerSizer), + TopSizer = wxBoxSizer:new(?wxVERTICAL), + wxSizer:add(TopSizer, Panel, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), + wxSizer:add(TopSizer, Buttons, [{flag, ?wxEXPAND}]), + wxWindow:setSizerAndFit(Dialog, TopSizer), + wxSizer:setSizeHints(TopSizer, Dialog), + wxCheckBox:connect(Check, command_checkbox_clicked, + [{callback, fun(#wx{event=#wxCommand{commandInt=Enable0}},_) -> + Enable = Enable0 > 0, + wxWindow:enable(Slider, [{enable, Enable}]) + end}]), + Res = case wxDialog:showModal(Dialog) of + ?wxID_OK -> + Enabled = wxCheckBox:isChecked(Check), + setup_timer(Enabled, {Timer, wxSlider:getValue(Slider)}); + ?wxID_CANCEL -> + {Timer, Value} + end, + wxDialog:destroy(Dialog), + Res. + +stop_timer(Timer = {false, _}) -> Timer; +stop_timer(Timer = {true, _}) -> Timer; +stop_timer(Timer = {_, Intv}) -> + setup_timer(false, Timer), + {true, Intv}. +start_timer(Intv) when is_integer(Intv) -> + setup_timer(true, {true, Intv}); +start_timer(Timer) -> + setup_timer(true, Timer). + +setup_timer(false, {Timer, Value}) + when is_boolean(Timer) -> + {false, Value}; +setup_timer(true, {false, Value}) -> + {ok, Timer} = timer:send_interval(Value * 1000, refresh_interval), + {Timer, Value}; +setup_timer(Bool, {Timer, Old}) -> + timer:cancel(Timer), + setup_timer(Bool, {false, Old}). + +display_info_dialog(Str) -> + Dlg = wxMessageDialog:new(wx:null(), Str), + wxMessageDialog:showModal(Dlg), + wxMessageDialog:destroy(Dlg), + ok. + +%% display_info(Parent, [{Title, [{Label, Info}]}]) -> {Panel, Sizer, InfoFieldsToUpdate} +display_info(Frame, Info) -> + Panel = wxPanel:new(Frame), + wxWindow:setBackgroundColour(Panel, {255,255,255}), + Sizer = wxBoxSizer:new(?wxVERTICAL), + wxSizer:addSpacer(Sizer, 5), + Add = fun(BoxInfo) -> + {Box, InfoFs} = create_box(Panel, BoxInfo), + wxSizer:add(Sizer, Box, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}]), + wxSizer:addSpacer(Sizer, 5), + InfoFs + end, + InfoFs = [Add(I) || I <- Info], + wxWindow:setSizerAndFit(Panel, Sizer), + {Panel, Sizer, InfoFs}. + +fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) -> + [{Str, get_value(Key, Data)} | fill_info(Rest, Data)]; +fill_info([{Str, {Format, Key}}|Rest], Data) + when is_atom(Key); is_function(Key), is_atom(Format) -> + [{Str, {Format, get_value(Key,Data)}} | fill_info(Rest, Data)]; +fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) -> + [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)]; +fill_info([{Str,Attrib,SubStructure}|Rest], Data) -> + [{Str, Attrib, fill_info(SubStructure, Data)}|fill_info(Rest,Data)]; +fill_info([], _) -> []. + +get_value(Key, Data) when is_atom(Key) -> + proplists:get_value(Key,Data); +get_value(Fun, Data) when is_function(Fun) -> + Fun(Data). + +update_info([Fields|Fs], [{_Header, SubStructure}| Rest]) -> + update_info2(Fields, SubStructure), + update_info(Fs, Rest); +update_info([Fields|Fs], [{_Header, _Attrib, SubStructure}| Rest]) -> + update_info2(Fields, SubStructure), + update_info(Fs, Rest); +update_info([], []) -> + ok. + +update_info2([Field|Fs], [{_Str, Value}|Rest]) -> + wxStaticText:setLabel(Field, to_str(Value)), + update_info2(Fs, Rest); +update_info2([], []) -> ok. + + +to_str(Value) when is_atom(Value) -> + atom_to_list(Value); +to_str({bytes, B}) -> + KB = B div 1024, + MB = KB div 1024, + if + MB > 10 -> integer_to_list(MB) ++ " mB"; + KB > 0 -> integer_to_list(KB) ++ " kB"; + true -> integer_to_list(B) ++ " B " + end; +to_str({time_ms, MS}) -> + S = MS div 1000, + Min = S div 60, + Hours = Min div 60, + Days = Hours div 24, + if + Days > 0 -> integer_to_list(Days) ++ " Days"; + Hours > 0 -> integer_to_list(Hours) ++ " Hours"; + Min > 0 -> integer_to_list(Min) ++ " Mins"; + true -> integer_to_list(S) ++ " Secs" + end; + +to_str({func, {F,A}}) when is_atom(F), is_integer(A) -> + lists:concat([F, "/", A]); +to_str({func, {F,'_'}}) when is_atom(F) -> + atom_to_list(F); +to_str({A, B}) when is_atom(A), is_atom(B) -> + lists:concat([A, ":", B]); +to_str({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> + lists:concat([M, ":", F, "/", A]); +to_str(Value) when is_list(Value) -> + case lists:all(fun(X) -> is_integer(X) end, Value) of + true -> Value; + false -> + lists:foldl(fun(X, Acc) -> + to_str(X) ++ " " ++ Acc end, + "", Value) + end; +to_str(Port) when is_port(Port) -> + erlang:port_to_list(Port); +to_str(Pid) when is_pid(Pid) -> + pid_to_list(Pid); +to_str(No) when is_integer(No) -> + integer_to_list(No); +to_str(Term) -> + io_lib:format("~w", [Term]). + +create_menus(Menus, MenuBar, Type) -> + Add = fun({Tag, Ms}, Index) -> + create_menu(Tag, Ms, Index, MenuBar, Type) + end, + [{First, _}|_] = Menus, + OnMac = os:type() =:= {unix, darwin}, + Index = if Type =:= default -> 0; + First =:= "File" -> 0; + OnMac -> 0; + true -> 1 + end, + wx:foldl(Add, Index, Menus), + ok. + +create_menu("File", MenuItems, Index, MenuBar, Type) -> + OnMac = os:type() =:= {unix, darwin}, + if OnMac, Type =:= default -> + Index; + not OnMac, Type =:= plugin -> + MenuId = wxMenuBar:findMenu(MenuBar, "File"), + Menu = wxMenuBar:getMenu(MenuBar, MenuId), + lists:foldl(fun(Record, N) -> + create_menu_item(Record, Menu, N) + end, 0, MenuItems), + Index + 1; + true -> + Menu = wxMenu:new(), + lists:foldl(fun(Record, N) -> + create_menu_item(Record, Menu, N) + end, 0, MenuItems), + wxMenuBar:insert(MenuBar, Index, Menu, "File"), + Index+1 + end; +create_menu(Name, MenuItems, Index, MenuBar, _Type) -> + Menu = wxMenu:new(), + lists:foldl(fun(Record, N) -> + create_menu_item(Record, Menu, N) + end, 0, MenuItems), + wxMenuBar:insert(MenuBar, Index, Menu, Name), + Index+1. + +create_menu_item(#create_menu{id = ?wxID_HELP=Id}, Menu, Index) -> + wxMenu:insert(Menu, Index, Id), + Index+1; +create_menu_item(#create_menu{id = Id, text = Text, type = Type, check = Check}, Menu, Index) -> + case Type of + append -> + wxMenu:insert(Menu, Index, Id, [{text, Text}]); + check -> + wxMenu:insertCheckItem(Menu, Index, Id, Text), + wxMenu:check(Menu, Id, Check); + radio -> + wxMenu:insertRadioItem(Menu, Index, Id, Text), + wxMenu:check(Menu, Id, Check); + separator -> + wxMenu:insertSeparator(Menu, Index) + end, + Index+1; +create_menu_item(separator, Menu, Index) -> + wxMenu:insertSeparator(Menu, Index), + Index+1. + +create_attrs() -> + Font = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + Text = case wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOXTEXT) of + {255,255,255,_} -> {10,10,10}; %% Is white on Mac for some reason + Color -> Color + end, + #attrs{even = wxListItemAttr:new(Text, ?BG_EVEN, Font), + odd = wxListItemAttr:new(Text, ?BG_ODD, Font), + deleted = wxListItemAttr:new(?FG_DELETED, ?BG_DELETED, Font), + changed = wxListItemAttr:new(Text, ?BG_CHANGED, Font), + searched = wxListItemAttr:new(Text, ?BG_SEARCHED, Font) + }. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_box_info({Title, List}) when is_list(List) -> {Title, ?wxALIGN_LEFT, List}; +get_box_info({Title, left, List}) -> {Title, ?wxALIGN_LEFT, List}; +get_box_info({Title, right, List}) -> {Title, ?wxALIGN_RIGHT, List}. + +create_box(Panel, Data) -> + {Title, Align, Info} = get_box_info(Data), + Box = wxStaticBoxSizer:new(?wxHORIZONTAL, Panel, [{label, Title}]), + Left = wxBoxSizer:new(?wxVERTICAL), + Right = wxBoxSizer:new(?wxVERTICAL), + Expand = [{flag, ?wxEXPAND}], + ExpAlign = [{flag, Align}], + AddRow = fun({Desc, Value}) -> + wxSizer:add(Left, wxStaticText:new(Panel, ?wxID_ANY, Desc ++ ":"), Expand), + Field = wxStaticText:new(Panel, ?wxID_ANY, to_str(Value)), + wxSizer:add(Right, Field, ExpAlign), + Field + end, + InfoFields = [AddRow(Entry) || Entry <- Info], + wxSizer:add(Box, Left), + wxSizer:addSpacer(Box, 10), + wxSizer:add(Box, Right), + wxSizer:addSpacer(Box, 30), + {Box, InfoFields}. diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl new file mode 100644 index 0000000000..cfc1c0665f --- /dev/null +++ b/lib/observer/src/observer_pro_wx.erl @@ -0,0 +1,608 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(observer_pro_wx). + +-behaviour(wx_object). + +-export([start_link/2]). + +%% wx_object callbacks +-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, + handle_event/2, handle_cast/2]). + +-include_lib("wx/include/wx.hrl"). +-include("../include/etop.hrl"). +-include("observer_defs.hrl"). +-include("etop_defs.hrl"). + +%% Defines +-define(COL_PID, 0). +-define(COL_NAME, 1). +-define(COL_TIME, 2). +-define(COL_REDS, 3). +-define(COL_MEM, 4). +-define(COL_MSG, 5). +-define(COL_FUN, 6). + +-define(ID_KILL, 201). +-define(ID_PROC, 202). +-define(ID_REFRESH, 203). +-define(ID_REFRESH_INTERVAL, 204). +-define(ID_DUMP_TO_FILE, 205). +-define(ID_TRACEMENU, 206). +-define(ID_TRACE_ALL_MENU, 207). +-define(ID_TRACE_NEW_MENU, 208). +-define(ID_ACCUMULATE, 209). + +%% Records + +-record(sort, + { + sort_key=?COL_REDS, + sort_incr=false + }). + +-record(holder, {parent, + info, + sort=#sort{}, + accum=[], + attrs, + node, + backend_pid + }). + +-record(state, {parent, + grid, + panel, + popup_menu, + parent_notebook, + timer, + procinfo_menu_pids=[], + sel={[], []}, + holder}). + +start_link(Notebook, Parent) -> + wx_object:start_link(?MODULE, [Notebook, Parent], []). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +init([Notebook, Parent]) -> + Attrs = observer_lib:create_attrs(), + Self = self(), + Holder = spawn_link(fun() -> init_table_holder(Self, Attrs) end), + {ProPanel, State} = setup(Notebook, Parent, Holder), + {ProPanel, State#state{holder=Holder}}. + +setup(Notebook, Parent, Holder) -> + ProPanel = wxPanel:new(Notebook, []), + + Grid = create_list_box(ProPanel, Holder), + Sizer = wxBoxSizer:new(?wxVERTICAL), + wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL}, + {proportion, 1}, + {border,4}]), + + wxWindow:setSizer(ProPanel, Sizer), + + Popup = create_popup_menu(ProPanel), + + State = #state{parent=Parent, + grid=Grid, + panel=ProPanel, + popup_menu=Popup, + parent_notebook=Notebook, + holder=Holder, + timer={false, 10} + }, + {ProPanel, State}. + + +%% UI-creation + +create_pro_menu(Parent, Holder) -> + MenuEntries = [{"File", + [#create_menu{id=?ID_DUMP_TO_FILE, text="Dump to file"}]}, + {"View", + [#create_menu{id=?ID_ACCUMULATE, text="Accumulate", + type=check, + check=call(Holder, {get_accum, self()})}, + separator, + #create_menu{id=?ID_REFRESH, text="Refresh\tCtrl-R"}, + #create_menu{id=?ID_REFRESH_INTERVAL, text="Refresh Interval"}]}, + {"Trace", + [#create_menu{id=?ID_TRACEMENU, text="Trace selected processes"}, + #create_menu{id=?ID_TRACE_NEW_MENU, text="Trace new processes"} + %% , #create_menu{id=?ID_TRACE_ALL_MENU, text="Trace all processes"} + ]} + ], + observer_wx:create_menus(Parent, MenuEntries). + +create_popup_menu(ParentFrame) -> + MiniFrame = wxMiniFrame:new(ParentFrame, ?wxID_ANY, "Options", [{style, ?wxFRAME_FLOAT_ON_PARENT}]), + Panel = wxPanel:new(MiniFrame), + Sizer = wxBoxSizer:new(?wxVERTICAL), + TraceBtn = wxButton:new(Panel, ?ID_TRACEMENU, [{label, "Trace selected"}, + {style, ?wxNO_BORDER}]), + ProcBtn = wxButton:new(Panel, ?ID_PROC, [{label, "Process info"}, + {style, ?wxNO_BORDER}]), + KillBtn = wxButton:new(Panel, ?ID_KILL, [{label, "Kill process"}, + {style, ?wxNO_BORDER}]), + + wxButton:connect(TraceBtn, command_button_clicked), + wxButton:connect(ProcBtn, command_button_clicked), + wxButton:connect(KillBtn, command_button_clicked), + wxSizer:add(Sizer, TraceBtn, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxSizer:add(Sizer, ProcBtn, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxSizer:add(Sizer, KillBtn, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxPanel:setSizer(Panel, Sizer), + wxSizer:setSizeHints(Sizer, MiniFrame), + MiniFrame. + +create_list_box(Panel, Holder) -> + Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_HRULES, + ListCtrl = wxListCtrl:new(Panel, [{style, Style}, + {onGetItemText, + fun(_, Row, Col) -> + call(Holder, {get_row, self(), Row, Col}) + end}, + {onGetItemAttr, + fun(_, Item) -> + call(Holder, {get_attr, self(), Item}) + end} + ]), + Li = wxListItem:new(), + AddListEntry = fun({Name, Align, DefSize}, Col) -> + wxListItem:setText(Li, Name), + wxListItem:setAlign(Li, Align), + wxListCtrl:insertColumn(ListCtrl, Col, Li), + wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize), + Col + 1 + end, + ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, 120}, + {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, 200}, + {"Time", ?wxLIST_FORMAT_CENTRE, 50}, + {"Reds", ?wxLIST_FORMAT_RIGHT, 100}, + {"Memory", ?wxLIST_FORMAT_RIGHT, 100}, + {"MsgQ", ?wxLIST_FORMAT_RIGHT, 50}, + {"Current Function", ?wxLIST_FORMAT_LEFT, 200}], + lists:foldl(AddListEntry, 0, ListItems), + wxListItem:destroy(Li), + + wxListCtrl:setItemCount(ListCtrl, 1), + wxListCtrl:connect(ListCtrl, size, [{skip, true}]), + wxListCtrl:connect(ListCtrl, command_list_item_activated), + wxListCtrl:connect(ListCtrl, command_list_item_right_click), + wxListCtrl:connect(ListCtrl, command_list_col_click), + %% Use focused instead of selected, selected doesn't generate events + %% for all multiple selections on Linux + wxListCtrl:connect(ListCtrl, command_list_item_focused), + ListCtrl. + +dump_to_file(Parent, FileName, Holder) -> + case file:open(FileName, [write]) of + {ok, Fd} -> + %% Holder closes the file when it's done + Holder ! {dump, Fd}; + {error, Reason} -> + FailMsg = file:format_error(Reason), + MD = wxMessageDialog:new(Parent, FailMsg), + wxDialog:showModal(MD), + wxDialog:destroy(MD) + end. + +start_procinfo(undefined, _Frame, Opened) -> + Opened; +start_procinfo(Pid, Frame, Opened) -> + case lists:member(Pid, Opened) of + true -> + Opened; + false -> + observer_procinfo:start(Pid, Frame, self()), + [Pid | Opened] + end. + +call(Holder, What) -> + Ref = erlang:monitor(process, Holder), + Holder ! What, + receive + {'DOWN', Ref, _, _, _} -> ""; + {Holder, Res} -> + erlang:demonitor(Ref), + Res + after 2000 -> + io:format("Hanging call ~p~n",[What]), + "" + end. + +%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +handle_info({holder_updated, Count}, State0=#state{grid=Grid}) -> + State = update_selection(State0), + + wxListCtrl:setItemCount(Grid, Count), + wxListCtrl:refreshItems(Grid, 0, Count-1), + + {noreply, State}; + +handle_info(refresh_interval, #state{holder=Holder}=State) -> + Holder ! refresh, + {noreply, State}; + +handle_info({procinfo_menu_closed, Pid}, + #state{procinfo_menu_pids=Opened}=State) -> + NewPids = lists:delete(Pid, Opened), + {noreply, State#state{procinfo_menu_pids=NewPids}}; + +handle_info({active, Node}, + #state{holder=Holder, timer=Timer, parent=Parent}=State) -> + create_pro_menu(Parent, Holder), + Holder ! {change_node, Node}, + {noreply, State#state{timer=observer_lib:start_timer(Timer)}}; + +handle_info(not_active, #state{timer=Timer0}=State) -> + Timer = observer_lib:stop_timer(Timer0), + {noreply, State#state{timer=Timer}}; + +handle_info({node, Node}, #state{holder=Holder}=State) -> + Holder ! {change_node, Node}, + {noreply, State}; + +handle_info(Info, State) -> + io:format("~p:~p, Unexpected info: ~p~n", [?MODULE, ?LINE, Info]), + {noreply, State}. + +terminate(_Reason, #state{holder=Holder}) -> + Holder ! stop, + etop:stop(), + ok. + +code_change(_, _, State) -> + {stop, not_yet_implemented, State}. + + +handle_call(Msg, _From, State) -> + io:format("~p:~p: Unhandled call ~p~n",[?MODULE, ?LINE, Msg]), + {reply, ok, State}. + + +handle_cast(Msg, State) -> + io:format("~p:~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]), + {noreply, State}. + +%%%%%%%%%%%%%%%%%%%%LOOP%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +handle_event(#wx{id=?ID_DUMP_TO_FILE}, #state{panel=Panel, holder=Holder}=State) -> + FD = wxFileDialog:new(Panel, + [{style,?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]), + case wxFileDialog:showModal(FD) of + ?wxID_OK -> + Path = wxFileDialog:getPath(FD), + wxDialog:destroy(FD), + dump_to_file(Panel, Path, Holder); + _ -> + wxDialog:destroy(FD) + end, + {noreply, State}; + +handle_event(#wx{id=?ID_ACCUMULATE, + event=#wxCommand{type=command_menu_selected, commandInt=CmdInt}}, + #state{holder=Holder}=State) -> + Holder ! {accum, CmdInt =:= 1}, + {noreply, State}; + +handle_event(#wx{id=?ID_REFRESH, event=#wxCommand{type=command_menu_selected}}, + #state{holder=Holder}=State) -> + Holder ! refresh, + {noreply, State}; + +handle_event(#wx{id=?ID_REFRESH_INTERVAL}, + #state{panel=Panel, timer=Timer0}=State) -> + Timer = observer_lib:interval_dialog(Panel, Timer0, 1, 5*60), + {noreply, State#state{timer=Timer}}; + +handle_event(#wx{id=?ID_KILL}, + #state{popup_menu=Pop,sel={[_|Ids], [ToKill|Pids]}}=State) -> + wxWindow:show(Pop, [{show, false}]), + exit(ToKill, kill), + {noreply, State#state{sel={Ids,Pids}}}; + + +handle_event(#wx{id = ?ID_PROC}, + #state{panel=Panel, + popup_menu=Pop, + sel={_, [Pid|_]}, + procinfo_menu_pids=Opened}=State) -> + wxWindow:show(Pop, [{show, false}]), + Opened2 = start_procinfo(Pid, Panel, Opened), + {noreply, State#state{procinfo_menu_pids=Opened2}}; + +handle_event(#wx{id = ?ID_TRACEMENU}, + #state{popup_menu=Pop, sel={_, Pids}, panel=Panel}=State) -> + wxWindow:show(Pop, [{show, false}]), + case Pids of + [] -> + observer_wx:create_txt_dialog(Panel, "No selected processes", "Tracer", ?wxICON_EXCLAMATION), + {noreply, State}; + Pids -> + observer_trace_wx:add_processes(observer_wx:get_tracer(), Pids), + {noreply, State} + end; + +handle_event(#wx{id=?ID_TRACE_NEW_MENU, event=#wxCommand{type=command_menu_selected}}, State) -> + observer_trace_wx:add_processes(observer_wx:get_tracer(), [new]), + {noreply, State}; + +handle_event(#wx{event=#wxSize{size={W,_}}}, + #state{grid=Grid}=State) -> + wx:batch(fun() -> + Cols = wxListCtrl:getColumnCount(Grid), + Last = lists:foldl(fun(I, Last) -> + Last - wxListCtrl:getColumnWidth(Grid, I) + end, W-Cols*3-?LCTRL_WDECR, lists:seq(0, Cols - 2)), + Size = max(200, Last), + %% io:format("Width ~p ~p => ~p~n",[W, Last, Size]), + wxListCtrl:setColumnWidth(Grid, Cols-1, Size) + end), + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_item_right_click, + itemIndex=Row}}, + #state{popup_menu=Popup, + holder=Holder}=State) -> + + case call(Holder, {get_row, self(), Row, pid}) of + {error, undefined} -> + wxWindow:show(Popup, [{show, false}]), + undefined; + {ok, _} -> + wxWindow:move(Popup, wx_misc:getMousePosition()), + wxWindow:show(Popup) + end, + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_item_focused, + itemIndex=Row}}, + #state{grid=Grid,popup_menu=Pop,holder=Holder} = State) -> + case Row >= 0 of + true -> + wxWindow:show(Pop, [{show, false}]), + SelIds = [Row|lists:delete(Row, get_selected_items(Grid))], + Pids = call(Holder, {get_pids, self(), SelIds}), + %% io:format("Focused ~p -> ~p~n",[State#state.sel, {SelIds, Pids}]), + {noreply, State#state{sel={SelIds, Pids}}}; + false -> + %% io:format("Focused -1~n",[]), + {noreply, State} + end; + +handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}}, + #state{holder=Holder}=State) -> + Holder ! {change_sort, Col}, + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_item_activated}}, + #state{panel=Panel, procinfo_menu_pids=Opened, + sel={_, [Pid|_]}}=State) + when Pid =/= undefined -> + Opened2 = start_procinfo(Pid, Panel, Opened), + {noreply, State#state{procinfo_menu_pids=Opened2}}; + +handle_event(Event, State) -> + io:format("~p:~p: handle event ~p\n", [?MODULE, ?LINE, Event]), + {noreply, State}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +update_selection(State=#state{holder=Holder, grid=Grid, + sel={SelIds0, SelPids0}}) -> + Sel = {SelIds,_SelPids} = call(Holder, {get_rows_from_pids, self(), SelPids0}), + set_focus(SelIds0, SelIds, Grid), + case SelIds =:= SelIds0 of + true -> ok; + false -> + wx:batch(fun() -> + [wxListCtrl:setItemState(Grid, I, 0, ?wxLIST_STATE_SELECTED) || + I <- SelIds0], + [wxListCtrl:setItemState(Grid, I, 16#FFFF, ?wxLIST_STATE_SELECTED) || + I <- SelIds] + end) + end, + %%io:format("Update ~p -> ~p~n",[{SelIds0, SelPids0}, Sel]), + State#state{sel=Sel}. + +get_selected_items(Grid) -> + get_selected_items(Grid, -1, []). + +get_selected_items(Grid, Index, ItemAcc) -> + Item = wxListCtrl:getNextItem(Grid, Index, [{geometry, ?wxLIST_NEXT_ALL}, + {state, ?wxLIST_STATE_SELECTED}]), + case Item of + -1 -> + lists:reverse(ItemAcc); + _ -> + get_selected_items(Grid, Item, [Item | ItemAcc]) + end. + +set_focus([], [], _Grid) -> ok; +set_focus([Same|_], [Same|_], _Grid) -> ok; +set_focus([], [New|_], Grid) -> + wxListCtrl:setItemState(Grid, New, 16#FFFF, ?wxLIST_STATE_FOCUSED); +set_focus([Old|_], [], Grid) -> + wxListCtrl:setItemState(Grid, Old, 0, ?wxLIST_STATE_FOCUSED); +set_focus([Old|_], [New|_], Grid) -> + wxListCtrl:setItemState(Grid, Old, 0, ?wxLIST_STATE_FOCUSED), + wxListCtrl:setItemState(Grid, New, 16#FFFF, ?wxLIST_STATE_FOCUSED). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%TABLE HOLDER%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init_table_holder(Parent, Attrs) -> + Backend = spawn_link(node(), observer_backend,etop_collect,[self()]), + table_holder(#holder{parent=Parent, + info=#etop_info{procinfo=[]}, + node=node(), + backend_pid=Backend, + attrs=Attrs + }). + +table_holder(#holder{info=#etop_info{procinfo=Info}, attrs=Attrs, + node=Node, backend_pid=Backend}=S0) -> + receive + {get_row, From, Row, Col} -> + get_row(From, Row, Col, Info), + table_holder(S0); + {get_attr, From, Row} -> + get_attr(From, Row, Attrs), + table_holder(S0); + {Backend, EtopInfo=#etop_info{}} -> + State = handle_update(EtopInfo, S0), + table_holder(State#holder{backend_pid=undefined}); + refresh when is_pid(Backend)-> + table_holder(S0); %% Already updating + refresh -> + Pid = spawn_link(Node,observer_backend,etop_collect,[self()]), + table_holder(S0#holder{backend_pid=Pid}); + {change_sort, Col} -> + State = change_sort(Col, S0), + table_holder(State); + {get_pids, From, Indices} -> + get_pids(From, Indices, Info), + table_holder(S0); + {get_rows_from_pids, From, Pids} -> + get_rows_from_pids(From, Pids, Info), + table_holder(S0); + + {get_node, From} -> + From ! {self(), Node}, + table_holder(S0); + {change_node, NewNode} -> + case Node == NewNode of + true -> + table_holder(S0); + false -> + self() ! refresh, + table_holder(S0#holder{node=NewNode}) + end; + {accum, Bool} -> + table_holder(change_accum(Bool,S0)); + {get_accum, From} -> + From ! {self(), S0#holder.accum == true}, + table_holder(S0); + {dump, Fd} -> + etop_txt:do_update(Fd, S0#holder.info, #opts{node=Node}), + file:close(Fd), + table_holder(S0); + stop -> + ok; + What -> + io:format("Table holder got ~p~n",[What]), + table_holder(S0) + end. + +change_sort(Col, S0=#holder{parent=Parent, info=EI=#etop_info{procinfo=Data}, sort=Sort0}) -> + {Sort, ProcInfo}=sort(Col, Sort0, Data), + Parent ! {holder_updated, length(Data)}, + S0#holder{info=EI#etop_info{procinfo=ProcInfo}, sort=Sort}. + +change_accum(true, S0) -> + S0#holder{accum=true}; +change_accum(false, S0=#holder{info=#etop_info{procinfo=Info}}) -> + self() ! refresh, + S0#holder{accum=lists:sort(Info)}. + +handle_update(EI=#etop_info{procinfo=ProcInfo0}, + S0=#holder{parent=Parent, sort=Sort=#sort{sort_key=KeyField}}) -> + {ProcInfo1, S1} = accum(ProcInfo0, S0), + {_SO, ProcInfo} = sort(KeyField, Sort#sort{sort_key=undefined}, ProcInfo1), + Parent ! {holder_updated, length(ProcInfo)}, + S1#holder{info=EI#etop_info{procinfo=ProcInfo}}. + +accum(ProcInfo, State=#holder{accum=true}) -> + {ProcInfo, State}; +accum(ProcInfo0, State=#holder{accum=Previous}) -> + ProcInfo = lists:sort(ProcInfo0), + {accum2(ProcInfo,Previous,[]), State#holder{accum=ProcInfo}}. + +accum2([PI=#etop_proc_info{pid=Pid, reds=Reds, runtime=RT}|PIs], + [#etop_proc_info{pid=Pid, reds=OldReds, runtime=OldRT}|Old], Acc) -> + accum2(PIs, Old, [PI#etop_proc_info{reds=Reds-OldReds, runtime=RT-OldRT}|Acc]); +accum2(PIs=[#etop_proc_info{pid=Pid}|_], [#etop_proc_info{pid=OldPid}|Old], Acc) + when Pid > OldPid -> + accum2(PIs, Old, Acc); +accum2([PI|PIs], Old, Acc) -> + accum2(PIs, Old, [PI|Acc]); +accum2([], _, Acc) -> Acc. + +sort(Col, Opt=#sort{sort_key=Col, sort_incr=Bool}, Table) -> + {Opt#sort{sort_incr=not Bool}, lists:reverse(Table)}; +sort(Col, S=#sort{sort_incr=true}, Table) -> + {S#sort{sort_key=Col}, lists:keysort(col_to_element(Col), Table)}; +sort(Col, S=#sort{sort_incr=false}, Table) -> + {S#sort{sort_key=Col}, lists:reverse(lists:keysort(col_to_element(Col), Table))}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_procinfo_data(Col, Info) -> + element(col_to_element(Col), Info). +col_to_element(?COL_PID) -> #etop_proc_info.pid; +col_to_element(?COL_NAME) -> #etop_proc_info.name; +col_to_element(?COL_MEM) -> #etop_proc_info.mem; +col_to_element(?COL_TIME) -> #etop_proc_info.runtime; +col_to_element(?COL_REDS) -> #etop_proc_info.reds; +col_to_element(?COL_FUN) -> #etop_proc_info.cf; +col_to_element(?COL_MSG) -> #etop_proc_info.mq. + +get_pids(From, Indices, ProcInfo) -> + Processes = [(lists:nth(I+1, ProcInfo))#etop_proc_info.pid || I <- Indices], + From ! {self(), Processes}. + +get_row(From, Row, pid, Info) -> + Pid = case Row =:= -1 of + true -> {error, undefined}; + false -> {ok, get_procinfo_data(?COL_PID, lists:nth(Row+1, Info))} + end, + From ! {self(), Pid}; +get_row(From, Row, Col, Info) -> + Data = case Row+1 > length(Info) of + true -> + ""; + false -> + ProcInfo = lists:nth(Row+1, Info), + get_procinfo_data(Col, ProcInfo) + end, + From ! {self(), observer_lib:to_str(Data)}. + +get_rows_from_pids(From, Pids0, Info) -> + Res = lists:foldl(fun(Pid, Data = {Ids, Pids}) -> + case index(Pid, Info, 0) of + false -> Data; + Index -> {[Index|Ids], [Pid|Pids]} + end + end, {[],[]}, Pids0), + From ! {self(), Res}. + +get_attr(From, Row, Attrs) -> + Attribute = case Row rem 2 =:= 0 of + true -> Attrs#attrs.even; + false -> Attrs#attrs.odd + end, + From ! {self(), Attribute}. + +index(Pid, [#etop_proc_info{pid=Pid}|_], Index) -> Index; +index(Pid, [_|PI], Index) -> index(Pid, PI, Index+1); +index(_, _, _) -> false. diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl new file mode 100644 index 0000000000..127599a39e --- /dev/null +++ b/lib/observer/src/observer_procinfo.erl @@ -0,0 +1,274 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer_procinfo). + +-behaviour(wx_object). + +-export([start/3]). + +-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, + handle_call/3, handle_info/2]). + +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). + +-define(REFRESH, 601). +-define(SELECT_ALL, 603). +-define(ID_NOTEBOOK, 604). + +-record(state, {parent, + frame, + pid, + pages=[] + }). + +-record(worker, {panel, callback}). + +start(Process, ParentFrame, Parent) -> + wx_object:start(?MODULE, [Process, ParentFrame, Parent], []). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init([Pid, ParentFrame, Parent]) -> + try + Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of + [] -> io_lib:format("~p",[Pid]); + {registered_name, Registered} -> atom_to_list(Registered) + end, + Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title], + [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {800,700}}]), + MenuBar = wxMenuBar:new(), + create_menus(MenuBar), + wxFrame:setMenuBar(Frame, MenuBar), + + Notebook = wxNotebook:new(Frame, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]), + + ProcessPage = init_panel(Notebook, "Process Information", Pid, fun init_process_page/2), + MessagePage = init_panel(Notebook, "Messages", Pid, fun init_message_page/2), + DictPage = init_panel(Notebook, "Dictionary", Pid, fun init_dict_page/2), + StackPage = init_panel(Notebook, "Stack Trace", Pid, fun init_stack_page/2), + + wxFrame:connect(Frame, close_window), + wxMenu:connect(Frame, command_menu_selected), + %% wxNotebook:connect(Notebook, command_notebook_page_changed, [{skip,true}]), + wxFrame:show(Frame), + {Frame, #state{parent=Parent, + pid=Pid, + frame=Frame, + pages=[ProcessPage,MessagePage,DictPage,StackPage] + }} + catch error:{badrpc, _} -> + observer_wx:return_to_localnode(ParentFrame, node(Pid)), + {stop, badrpc, #state{parent=Parent, pid=Pid}}; + Error:Reason -> + io:format("~p:~p: ~p ~p~n ~p~n", + [?MODULE, ?LINE, Error, Reason, erlang:get_stacktrace()]) + end. + +init_panel(Notebook, Str, Pid, Fun) -> + Panel = wxPanel:new(Notebook), + Sizer = wxBoxSizer:new(?wxHORIZONTAL), + {Window,Callback} = Fun(Panel, Pid), + wxSizer:add(Sizer, Window, [{flag, ?wxEXPAND bor ?wxALL}, {proportion, 1}, {border, 5}]), + wxPanel:setSizer(Panel, Sizer), + true = wxNotebook:addPage(Notebook, Panel, Str), + #worker{panel=Panel, callback=Callback}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Callbacks%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_event(#wx{event=#wxClose{type=close_window}}, State) -> + {stop, shutdown, State}; + +handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) -> + {stop, shutdown, State}; + +handle_event(#wx{id=?REFRESH}, #state{pages=Pages}=State) -> + [(W#worker.callback)() || W <- Pages], + {noreply, State}; + +handle_event(Event, State) -> + io:format("~p: ~p, Handle event: ~p~n", [?MODULE, ?LINE, Event]), + {noreply, State}. + +handle_info(Info, State) -> + io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]), + {noreply, State}. + +handle_call(Call, _From, State) -> + io:format("~p ~p: Got call ~p~n",[?MODULE, ?LINE, Call]), + {reply, ok, State}. + +handle_cast(Cast, State) -> + io:format("~p ~p: Got cast ~p~n", [?MODULE, ?LINE, Cast]), + {noreply, State}. + +terminate(_Reason, #state{parent=Parent,pid=Pid,frame=Frame}) -> + Parent ! {procinfo_menu_closed, Pid}, + case Frame of + undefined -> ok; + _ -> wxFrame:destroy(Frame) + end, + ok. + +code_change(_, _, State) -> + {stop, not_yet_implemented, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +init_process_page(Panel, Pid) -> + Fields = process_info_fields(Pid), + {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields), + {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}. + +init_text_page(Parent) -> + Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY, + Text = wxTextCtrl:new(Parent, ?wxID_ANY, [{style, Style}]), + Font = observer_wx:get_attrib({font, fixed}), + Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]), + true = wxTextCtrl:setDefaultStyle(Text, Attr), + wxTextAttr:destroy(Attr), + Text. + +init_message_page(Parent, Pid) -> + Text = init_text_page(Parent), + Format = fun(Message, Number) -> + {io_lib:format("~-4.w ~p~n", [Number, Message]), + Number+1} + end, + Update = fun() -> + {messages,RawMessages} = + observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]), + {Messages,_} = lists:mapfoldl(Format, 1, RawMessages), + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + case Messages =:= [] of + true -> + wxTextCtrl:writeText(Text, "No messages"); + false -> + wxTextCtrl:writeText(Text, Messages) + end + end, + Update(), + {Text, Update}. + +init_dict_page(Parent, Pid) -> + Text = init_text_page(Parent), + Update = fun() -> + {dictionary,RawDict} = + observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]), + Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict], + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + wxTextCtrl:writeText(Text, Dict) + end, + Update(), + {Text, Update}. + +init_stack_page(Parent, Pid) -> + Text = init_text_page(Parent), + Format = fun({Mod, Fun, Arg, Info}) -> + Str = io_lib:format("~w:~w/~w", [Mod,Fun,Arg]), + case Info of + [{file,File},{line,Line}] -> + io_lib:format("~-45.s ~s:~w~n", [Str,File,Line]); + _ -> + [Str,$\n] + end + end, + Update = fun() -> + {current_stacktrace,RawBt} = + observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, current_stacktrace]), + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + [wxTextCtrl:writeText(Text, Format(Entry)) || Entry <- RawBt] + end, + Update(), + {Text, Update}. + +create_menus(MenuBar) -> + Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]}, + {"View", [#create_menu{id=?REFRESH, text="Refresh\tCtrl-R"}]}], + observer_lib:create_menus(Menus, MenuBar, new_window). + +process_info_fields(Pid) -> + RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]), + Struct = [{"Overview", + [{"Initial Call", initial_call}, + {"Current Function", current_function}, + {"Registered Name", registered_name}, + {"Status", status}, + {"Message Queue Len",message_queue_len}, + {"Priority", priority}, + {"Trap Exit", trap_exit}, + {"Reductions", reductions}, + {"Binary", binary}, + {"Last Calls", last_calls}, + {"Catch Level", catchlevel}, + {"Trace", trace}, + {"Suspending", suspending}, + {"Sequential Trace Token", sequential_trace_token}, + {"Error Handler", error_handler}]}, + {"Connections", + [{"Group Leader", group_leader}, + {"Links", links}, + {"Monitors", monitors}, + {"Monitored by", monitored_by}]}, + {"Memory and Garbage Collection", right, + [{"Memory", {bytes, memory}}, + {"Stack and Heaps", {bytes, total_heap_size}}, + {"Heap Size", {bytes, heap_size}}, + {"Stack Size", {bytes, stack_size}}, + {"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}}, + {"GC FullSweep After", get_gc_info(fullsweep_after)} + ]}], + observer_lib:fill_info(Struct, RawInfo). + +item_list() -> + [ %% backtrace, + binary, + catchlevel, + current_function, + %% dictionary, + error_handler, + garbage_collection, + group_leader, + heap_size, + initial_call, + last_calls, + links, + memory, + message_queue_len, + %% messages, + monitored_by, + monitors, + priority, + reductions, + registered_name, + sequential_trace_token, + stack_size, + status, + suspending, + total_heap_size, + trace, + trap_exit]. + +get_gc_info(Arg) -> + fun(Data) -> + GC = proplists:get_value(garbage_collection, Data), + proplists:get_value(Arg, GC) + end. diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl new file mode 100644 index 0000000000..ddedcf3829 --- /dev/null +++ b/lib/observer/src/observer_sys_wx.erl @@ -0,0 +1,223 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(observer_sys_wx). + +-behaviour(wx_object). + +-export([start_link/2]). +%% wx_object callbacks +-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, + handle_event/2, handle_cast/2]). + +-export([sys_info/0]). + +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). + +-define(ID_REFRESH, 101). +-define(ID_REFRESH_INTERVAL, 102). + +%% Records +-record(sys_wx_state, + {parent, + node, + parent_notebook, + panel, sizer, + menubar, + fields, + timer}). + +start_link(Notebook, Parent) -> + wx_object:start_link(?MODULE, [Notebook, Parent], []). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init([Notebook, Parent]) -> + SysInfo = sys_info(), + {Info, Stat} = info_fields(), + Panel = wxPanel:new(Notebook), + Sizer = wxBoxSizer:new(?wxHORIZONTAL), + {FPanel0, _FSizer0, Fields0} = + observer_lib:display_info(Panel, observer_lib:fill_info(Info, SysInfo)), + {FPanel1, _FSizer1, Fields1} = + observer_lib:display_info(Panel, observer_lib:fill_info(Stat, SysInfo)), + wxSizer:add(Sizer, FPanel0, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxLEFT}, + {proportion, 1}, {border, 5}]), + wxSizer:add(Sizer, FPanel1, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxRIGHT}, + {proportion, 1}, {border, 5}]), + wxPanel:setSizer(Panel, Sizer), + Timer = observer_lib:start_timer(10), + {Panel, #sys_wx_state{parent=Parent, + parent_notebook=Notebook, + panel=Panel, sizer=Sizer, + timer=Timer, fields=Fields0 ++ Fields1}}. + +create_sys_menu(Parent) -> + View = {"View", [#create_menu{id = ?ID_REFRESH, text = "Refresh\tCtrl-R"}, + #create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh interval"}]}, + observer_wx:create_menus(Parent, [View]). + +update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) -> + SysInfo = observer_wx:try_rpc(Node, ?MODULE, sys_info, []), + {Info, Stat} = info_fields(), + observer_lib:update_info(Fields, observer_lib:fill_info(Info, SysInfo) ++ + observer_lib:fill_info(Stat, SysInfo)), + wxSizer:layout(Sizer). + +info_fields() -> + Info = [{"System and Architecture", + [{"System Version", otp_release}, + {"Erts Version", version}, + {"Compiled for", system_architecture}, + {"Emulator Wordsize", wordsize_external}, + {"Process Wordsize", wordsize_internal}, + {"Smp Support", smp_support}, + {"Thread Support", threads}, + {"Async thread pool size", thread_pool_size} + ]}, + {"CPU's and Threads", + [{"System Logical CPU's", logical_processors}, + {"Erlang Logical CPU's", logical_processors_online}, + {"Used Logical CPU's", logical_processors_available} + ]} + ], + Stat = [{"Memory Usage", right, + [{"Total", total}, + {"Processes", processes}, + {"Atoms", atom}, + {"Binaries", binary}, + {"Code", code}, + {"Ets", ets} + ]}, + {"Statistics", right, + [{"Up time", uptime}, + {"Max Processes", process_limit}, + {"Processes", process_count}, + {"Run Queue", run_queue}, + {"IO Input", io_input}, + {"IO Output", io_output} + ]} + ], + {Info, Stat}. + +%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +handle_info(refresh_interval, #sys_wx_state{panel = Panel, + node = Node} = State) -> + try + update_syspage(State) + catch error:{badrpc, _} -> + observer_wx:return_to_localnode(Panel, Node) + end, + {noreply, State}; + +handle_info({node, Node}, #sys_wx_state{panel = Panel} = State) -> + UpdState = State#sys_wx_state{node = Node}, + try + update_syspage(UpdState), + {noreply, UpdState} + catch error:{badrpc, _} -> + observer_wx:return_to_localnode(Panel, Node), + {noreply, State} + end; + +handle_info({active, Node}, #sys_wx_state{parent = Parent, panel = Panel, + timer = Timer} = State) -> + UpdState = State#sys_wx_state{node = Node}, + create_sys_menu(Parent), + try + update_syspage(UpdState), + {noreply, UpdState#sys_wx_state{timer=observer_lib:start_timer(Timer)}} + catch error:{badrpc, _} -> + observer_wx:return_to_localnode(Panel, Node), + {noreply, State} + end; + + +handle_info(not_active, #sys_wx_state{timer = Timer} = State) -> + {noreply, State#sys_wx_state{timer = observer_lib:stop_timer(Timer)}}; + +handle_info(Info, State) -> + io:format("~p:~p: Unhandled info: ~p~n", [?MODULE, ?LINE, Info]), + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_, _, State) -> + {stop, not_yet_implemented, State}. + +handle_call(Msg, _From, State) -> + io:format("~p~p: Unhandled Call ~p~n",[?MODULE, ?LINE, Msg]), + {reply, ok, State}. + +handle_cast(Msg, State) -> + io:format("~p~p: Unhandled cast ~p~n",[?MODULE, ?LINE, Msg]), + {noreply, State}. + +handle_event(#wx{id = ?ID_REFRESH, event = #wxCommand{type = command_menu_selected}}, + #sys_wx_state{node = Node, panel = Panel} = State) -> + try + update_syspage(State) + catch error:{badrpc, _} -> + observer_wx:return_to_localnode(Panel, Node) + end, + {noreply, State}; + +handle_event(#wx{id = ?ID_REFRESH_INTERVAL, + event = #wxCommand{type = command_menu_selected}}, + #sys_wx_state{timer = Timer0, parent_notebook = Notebook} = State) -> + Timer = observer_lib:interval_dialog(Notebook, Timer0, 1, 5*60), + {noreply, State#sys_wx_state{timer=Timer}}; + +handle_event(Event, State) -> + io:format("~p:~p: Unhandled event ~p\n", [?MODULE,?LINE,Event]), + {noreply, State}. + + +sys_info() -> + {{_,Input},{_,Output}} = erlang:statistics(io), + [{process_count, erlang:system_info(process_count)}, + {process_limit, erlang:system_info(process_limit)}, + {uptime, {time_ms, element(1, erlang:statistics(wall_clock))}}, + {run_queue, erlang:statistics(run_queue)}, + {io_input, {bytes, Input}}, + {io_output, {bytes, Output}}, + {logical_processors, erlang:system_info(logical_processors)}, + {logical_processors_available, erlang:system_info(logical_processors_available)}, + {logical_processors_online, erlang:system_info(logical_processors_online)}, + + {total, {bytes, erlang:memory(total)}}, + %%{processes_used, erlang:memory(processes_used)}, + {processes, {bytes, erlang:memory(processes)}}, + %%{atom_used, erlang:memory(atom_used)}, + {atom, {bytes, erlang:memory(atom)}}, + {binary, {bytes, erlang:memory(binary)}}, + {code, {bytes, erlang:memory(code)}}, + {ets, {bytes, erlang:memory(ets)}}, + + {otp_release, erlang:system_info(otp_release)}, + {version, erlang:system_info(version)}, + {system_architecture, erlang:system_info(system_architecture)}, + {kernel_poll, erlang:system_info(kernel_poll)}, + {smp_support, erlang:system_info(smp_support)}, + {threads, erlang:system_info(threads)}, + {thread_pool_size, erlang:system_info(thread_pool_size)}, + {wordsize_internal, erlang:system_info({wordsize, internal})}, + {wordsize_external, erlang:system_info({wordsize, external})} + ]. diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl new file mode 100644 index 0000000000..0ab7db121b --- /dev/null +++ b/lib/observer/src/observer_trace_wx.erl @@ -0,0 +1,628 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer_trace_wx). + +-export([start_link/2, add_processes/2]). +-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, + handle_event/2, handle_cast/2]). + +-behaviour(wx_object). + +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). + +-define(OPTIONS, 301). +-define(SAVE_BUFFER, 302). +-define(CLOSE, 303). +-define(CLEAR, 304). +-define(SAVE_TRACEOPTS, 305). +-define(LOAD_TRACEOPTS, 306). +-define(TOGGLE_TRACE, 307). +-define(ADD_NEW, 308). +-define(ADD_TP, 309). +-define(PROCESSES, 350). +-define(MODULES, 351). +-define(FUNCTIONS, 352). +-define(TRACERWIN, 353). + +-record(state, + {parent, + panel, + p_view, + m_view, + f_view, + nodes = [], + toggle_button, + tpids = [], %% #tpid + def_trace_opts = [], + tpatterns = dict:new(), % Key =:= Module::atom, Value =:= {M, F, A, MatchSpec} + match_specs = []}). % [ #match_spec{} ] + +-record(tpid, {pid, opts}). + +start_link(Notebook, ParentPid) -> + wx_object:start_link(?MODULE, [Notebook, ParentPid], []). + +add_processes(Tracer, Pids) when is_list(Pids) -> + wx_object:cast(Tracer, {add_processes, Pids}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init([Notebook, ParentPid]) -> + wx:batch(fun() -> create_window(Notebook, ParentPid) end). + +create_window(Notebook, ParentPid) -> + %% Create the window + Panel = wxPanel:new(Notebook, [{size, wxWindow:getClientSize(Notebook)}]), + Sizer = wxBoxSizer:new(?wxVERTICAL), + Splitter = wxSplitterWindow:new(Panel, [{size, wxWindow:getClientSize(Panel)}]), + ProcessView = create_process_view(Splitter), + {MatchSpecView,ModView,FuncView} = create_matchspec_view(Splitter), + wxSplitterWindow:setSashGravity(Splitter, 0.5), + wxSplitterWindow:setMinimumPaneSize(Splitter,50), + wxSplitterWindow:splitHorizontally(Splitter, ProcessView, MatchSpecView), + wxSizer:add(Sizer, Splitter, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}, {proportion, 1}]), + %% Buttons + Buttons = wxBoxSizer:new(?wxHORIZONTAL), + ToggleButton = wxToggleButton:new(Panel, ?TOGGLE_TRACE, "Start Trace", []), + wxSizer:add(Buttons, ToggleButton), + New = wxButton:new(Panel, ?ADD_NEW, [{label, "Trace New Processes"}]), + wxSizer:add(Buttons, New), + ATP = wxButton:new(Panel, ?ADD_TP, [{label, "Add Trace Pattern"}]), + wxSizer:add(Buttons, ATP), + wxMenu:connect(Panel, command_togglebutton_clicked, []), + wxMenu:connect(Panel, command_button_clicked, []), + wxSizer:add(Sizer, Buttons, [{flag, ?wxALL},{border, 2}, {proportion,0}]), + wxWindow:setSizer(Panel, Sizer), + {Panel, #state{parent=ParentPid, panel=Panel, + p_view=ProcessView, m_view=ModView, f_view=FuncView, + toggle_button = ToggleButton, + match_specs=default_matchspecs()}}. + +default_matchspecs() -> + Ms = [{"Return Trace", [{'_', [], [{return_trace}]}], "fun(_) -> return_trace() end"}, + {"Exception Trace", [{'_', [], [{exception_trace}]}], "fun(_) -> exception_trace() end"}, + {"Message Caller", [{'_', [], [{message,{caller}}]}], "fun(_) -> message(caller()) end"}, + {"Message Dump", [{'_', [], [{message,{process_dump}}]}], "fun(_) -> message(process_dump()) end"}], + [make_ms(Name,Term,FunStr) || {Name,Term,FunStr} <- Ms]. + +create_process_view(Parent) -> + Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, + Grid = wxListCtrl:new(Parent, [{winid, ?PROCESSES}, {style, Style}]), + Li = wxListItem:new(), + AddListEntry = fun({Name, Align, DefSize}, Col) -> + wxListItem:setText(Li, Name), + wxListItem:setAlign(Li, Align), + wxListCtrl:insertColumn(Grid, Col, Li), + wxListCtrl:setColumnWidth(Grid, Col, DefSize), + Col + 1 + end, + ListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, 120}, + {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}], + lists:foldl(AddListEntry, 0, ListItems), + wxListItem:destroy(Li), + + %% wxListCtrl:connect(Grid, command_list_item_activated), + %% wxListCtrl:connect(Grid, command_list_item_selected), + wxListCtrl:connect(Grid, size, [{skip, true}]), + + wxWindow:setFocus(Grid), + Grid. + +create_matchspec_view(Parent) -> + Panel = wxPanel:new(Parent), + MainSz = wxBoxSizer:new(?wxHORIZONTAL), + Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, + Splitter = wxSplitterWindow:new(Panel, []), + Modules = wxListCtrl:new(Splitter, [{winid, ?MODULES}, {style, Style}]), + Funcs = wxListCtrl:new(Splitter, [{winid, ?FUNCTIONS}, {style, Style}]), + Li = wxListItem:new(), + wxListItem:setText(Li, "Modules"), + wxListCtrl:insertColumn(Modules, 0, Li), + wxListItem:setText(Li, "Functions"), + wxListCtrl:insertColumn(Funcs, 0, Li), + wxListCtrl:setColumnWidth(Funcs, 0, 150), + wxListItem:setText(Li, "Match Spec"), + wxListCtrl:insertColumn(Funcs, 1, Li), + wxListCtrl:setColumnWidth(Funcs, 1, 300), + wxListItem:destroy(Li), + wxSplitterWindow:setSashGravity(Splitter, 0.0), + wxSplitterWindow:setMinimumPaneSize(Splitter,50), + wxSplitterWindow:splitVertically(Splitter, Modules, Funcs, [{sashPosition, 150}]), + wxSizer:add(MainSz, Splitter, [{flag, ?wxEXPAND}, {proportion, 1}]), + + wxListCtrl:connect(Modules, size, [{skip, true}]), + wxListCtrl:connect(Funcs, size, [{skip, true}]), + wxListCtrl:connect(Modules, command_list_item_selected), + %% wxListCtrl:connect(Funcs, command_list_item_selected), + wxPanel:setSizer(Panel, MainSz), + {Panel, Modules, Funcs}. + +create_menues(Parent) -> + Menus = [{"File", [#create_menu{id = ?LOAD_TRACEOPTS, text = "Load settings"}, + #create_menu{id = ?SAVE_TRACEOPTS, text = "Save settings"}] + }], + observer_wx:create_menus(Parent, Menus). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%Main window +handle_event(#wx{obj=Obj, event=#wxSize{size={W,_}}}, State) -> + case wx:getObjectType(Obj) =:= wxListCtrl of + true -> + wx:batch(fun() -> + Cols = wxListCtrl:getColumnCount(Obj), + Last = lists:foldl(fun(I, Last) -> + Last - wxListCtrl:getColumnWidth(Obj, I) + end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)), + Size = max(150, Last), + wxListCtrl:setColumnWidth(Obj, Cols-1, Size) + end); + false -> + ok + end, + {noreply, State}; + +handle_event(#wx{id=?ADD_NEW}, State = #state{panel=Parent, def_trace_opts=TraceOpts}) -> + case observer_traceoptions_wx:process_trace(Parent, TraceOpts) of + {ok, Opts} -> + Process = #tpid{pid=new, opts=Opts}, + {noreply, do_add_processes([Process], State#state{def_trace_opts=Opts})}; + cancel -> + {noreply, State} + end; + +handle_event(#wx{id=?ADD_TP}, + State = #state{panel=Parent, nodes=Nodes, match_specs=Ms}) -> + Node = case Nodes of + [N|_] -> N; + [] -> node() + end, + case observer_traceoptions_wx:trace_pattern(self(), Parent, Node, Ms) of + cancel -> + {noreply, State}; + Patterns -> + {noreply, do_add_patterns(Patterns, State)} + end; + +handle_event(#wx{id=?MODULES, event=#wxList{type=command_list_item_selected, itemIndex=Row}}, + State = #state{tpatterns=TPs, m_view=Mview, f_view=Fview}) -> + Module = list_to_atom(wxListCtrl:getItemText(Mview, Row)), + update_functions_view(dict:fetch(Module, TPs), Fview), + {noreply, State}; + + +handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 1}}, + #state{panel = Panel, + nodes = Nodes, + tpids = TProcs, + tpatterns = TPs, + toggle_button = ToggleBtn} = State) -> + LogWin = wxFrame:new(Panel, ?TRACERWIN, "Trace Log", [{size, {750, 800}}]), + Text = wxTextCtrl:new(LogWin, ?wxID_ANY, + [{style, ?wxTE_MULTILINE bor ?wxTE_RICH2 bor + ?wxTE_DONTWRAP bor ?wxTE_READONLY}]), + Font = observer_wx:get_attrib({font, fixed}), + Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]), + true = wxTextCtrl:setDefaultStyle(Text, Attr), + Env = wx:get_env(), + Write = fun(Trace) -> + wx:set_env(Env), + wxTextCtrl:appendText(Text, textformat(Trace)) + end, + {ok, _} = ttb:tracer(Nodes, [{file, {local,"/tmp/foo"}}, {shell, {only, Write}}]), + setup_ttb(dict:to_list(TPs), TProcs), + wxFrame:connect(LogWin, close_window, [{skip, true}]), + wxFrame:show(LogWin), + wxToggleButton:setLabel(ToggleBtn, "Stop Trace"), + {noreply, State}; + +handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 0}}, + #state{toggle_button = ToggleBtn} = State) -> + %%Stop tracing + ttb:stop(nofetch), + wxToggleButton:setLabel(ToggleBtn, "Start Trace"), + {noreply, State}; + +handle_event(#wx{id=?TRACERWIN, event=#wxClose{}}, + #state{toggle_button = ToggleBtn} = State) -> + %%Stop tracing + ttb:stop(nofetch), + wxToggleButton:setLabel(ToggleBtn, "Start Trace"), + {noreply, State}; + +%% handle_event(#wx{id = ?CLEAR, event = #wxCommand{type = command_menu_selected}}, +%% #state{text_ctrl = TxtCtrl} = State) -> +%% wxTextCtrl:clear(TxtCtrl), +%% {noreply, State}; + +%% handle_event(#wx{id = ?SAVE_BUFFER, event = #wxCommand{type = command_menu_selected}}, +%% #state{frame = Frame, text_ctrl = TxtCtrl} = State) -> +%% Dialog = wxFileDialog:new(Frame, [{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]), +%% case wxFileDialog:showModal(Dialog) of +%% ?wxID_OK -> +%% Path = wxFileDialog:getPath(Dialog), +%% wxDialog:destroy(Dialog), +%% case filelib:is_file(Path) of +%% true -> +%% observer_wx:create_txt_dialog(Frame, "File already exists: " ++ Path ++ "\n", +%% "Error", ?wxICON_ERROR); +%% false -> +%% wxTextCtrl:saveFile(TxtCtrl, [{file, Path}]) +%% end; +%% _ -> +%% wxDialog:destroy(Dialog), +%% ok +%% end, +%% {noreply, State}; + +handle_event(#wx{id = ?SAVE_TRACEOPTS, + event = #wxCommand{type = command_menu_selected}}, + #state{panel = Panel, + def_trace_opts = TraceOpts, + match_specs = MatchSpecs, + tpatterns = TracePatterns + } = State) -> + Dialog = wxFileDialog:new(Panel, [{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]), + case wxFileDialog:showModal(Dialog) of + ?wxID_OK -> + Path = wxFileDialog:getPath(Dialog), + write_file(Panel, Path, TraceOpts, MatchSpecs, dict:to_list(TracePatterns)); + _ -> + ok + end, + wxDialog:destroy(Dialog), + {noreply, State}; + +handle_event(#wx{id = ?LOAD_TRACEOPTS, + event = #wxCommand{type = command_menu_selected}}, + #state{panel = Panel} = State) -> + Dialog = wxFileDialog:new(Panel, [{style, ?wxFD_FILE_MUST_EXIST}]), + State2 = case wxFileDialog:showModal(Dialog) of + ?wxID_OK -> + Path = wxFileDialog:getPath(Dialog), + read_settings(Path, State); + _ -> + State + end, + wxDialog:destroy(Dialog), + {noreply, State2}; + +handle_event(#wx{id=ID, event = What}, State) -> + io:format("~p:~p: Unhandled event: ~p, ~p ~n", [?MODULE, self(), ID, What]), + {noreply, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_call(Msg, _From, State) -> + io:format("~p~p: Got Call ~p~n",[?MODULE, ?LINE, Msg]), + {reply, ok, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_cast({add_processes, Pids}, State = #state{panel=Parent, def_trace_opts=TraceOpts}) -> + case observer_traceoptions_wx:process_trace(Parent, TraceOpts) of + {ok, Opts} -> + POpts = [#tpid{pid=Pid, opts=Opts} || Pid <- Pids], + {noreply, do_add_processes(POpts, State#state{def_trace_opts=Opts})}; + cancel -> + {noreply, State} + end; +handle_cast(Msg, State) -> + io:format("~p ~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]), + {noreply, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +handle_info({active, _Node}, State=#state{parent=Parent}) -> + create_menues(Parent), + {noreply, State}; + +handle_info(not_active, State) -> + {noreply, State}; + +handle_info({update_ms, NewMs}, State) -> + {noreply, State#state{match_specs=NewMs}}; + +handle_info(Any, State) -> + io:format("~p~p: received unexpected message: ~p\n", [?MODULE, self(), Any]), + {noreply, State}. + +terminate(_Reason, #state{nodes=_Nodes}) -> + %% case observer_wx:try_rpc(Node, erlang, whereis, [dbg]) of + %% undefined -> fine; + %% Pid -> exit(Pid, kill) + %% end, + ok. + +code_change(_, _, State) -> + {stop, not_yet_implemented, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +do_add_processes(POpts, S0=#state{p_view=LCtrl, tpids=OldPids, nodes=Ns0}) -> + case merge_pids(POpts, OldPids) of + {OldPids, [], []} -> + S0; + {Pids, New, _Changed} -> + update_process_view(Pids, LCtrl), + Ns1 = lists:usort([node(Pid) || #tpid{pid=Pid} <- New, is_pid(Pid)]), + Nodes = case ordsets:subtract(Ns1, Ns0) of + [] -> Ns0; %% No new Nodes + NewNs -> + %% Handle new nodes + %% BUGBUG add trace patterns for new nodes + ordsets:union(NewNs, Ns0) + end, + S0#state{tpids=Pids, nodes=Nodes} + end. + +update_process_view(Pids, LCtrl) -> + wxListCtrl:deleteAllItems(LCtrl), + wx:foldl(fun(#tpid{pid=Pid, opts=Opts}, Row) -> + _Item = wxListCtrl:insertItem(LCtrl, Row, ""), + ?EVEN(Row) andalso + wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str(Pid)), + wxListCtrl:setItem(LCtrl, Row, 1, observer_lib:to_str(Opts)), + Row+1 + end, 0, Pids). + +do_add_patterns({Module, NewPs}, State=#state{tpatterns=TPs0, m_view=Mview, f_view=Fview}) -> + Old = case dict:find(Module, TPs0) of + {ok, Prev} -> Prev; + error -> [] + end, + case merge_patterns(NewPs, Old) of + {Old, [], []} -> + State; + {MPatterns, _New, _Changed} -> + TPs = dict:store(Module, MPatterns, TPs0), + update_modules_view(lists:sort(dict:fetch_keys(TPs)), Module, Mview), + update_functions_view(dict:fetch(Module, TPs), Fview), + State#state{tpatterns=TPs} + end. + +update_modules_view(Mods, Module, LCtrl) -> + wxListCtrl:deleteAllItems(LCtrl), + wx:foldl(fun(Mod, Row) -> + _Item = wxListCtrl:insertItem(LCtrl, Row, ""), + ?EVEN(Row) andalso + wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str(Mod)), + (Mod =:= Module) andalso + wxListCtrl:setItemState(LCtrl, Row, 16#FFFF, ?wxLIST_STATE_SELECTED), + Row+1 + end, 0, Mods). + +update_functions_view(Funcs, LCtrl) -> + wxListCtrl:deleteAllItems(LCtrl), + wx:foldl(fun(#tpattern{fa=FA, ms=#match_spec{str=Ms}}, Row) -> + _Item = wxListCtrl:insertItem(LCtrl, Row, ""), + ?EVEN(Row) andalso wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({func,FA})), + wxListCtrl:setItem(LCtrl, Row, 1, Ms), + Row+1 + end, 0, Funcs). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +merge_pids([N1=#tpid{pid=new}|Ns], [N2=#tpid{pid=new}|Old]) -> + {Pids, New, Changed} = merge_pids_1(Ns,Old), + {[N1|Pids], New, [{N2,N2}|Changed]}; +merge_pids([N1=#tpid{pid=new}|Ns], Old) -> + {Pids, New, Changed} = merge_pids_1(Ns,Old), + {[N1|Pids], [N1|New], Changed}; +merge_pids(Ns, [N2=#tpid{pid=new}|Old]) -> + {Pids, New, Changed} = merge_pids_1(Ns,Old), + {[N2|Pids], New, Changed}; +merge_pids(New, Old) -> + merge_pids_1(New, Old). + +merge_pids_1(New, Old) -> + merge(lists:sort(New), Old, #tpid.pid, [], [], []). + +merge_patterns(New, Old) -> + merge(lists:sort(New), Old, #tpattern.fa, [], [], []). + + +merge([N|Ns], [N|Os], El, New, Ch, All) -> + merge(Ns, Os, El, New, Ch, [N|All]); +merge([N|Ns], [O|Os], El, New, Ch, All) + when element(El, N) == element(El, O) -> + merge(Ns, Os, El, New, [{O,N}|Ch], [N|All]); +merge([N|Ns], Os=[O|_], El, New, Ch, All) + when element(El, N) < element(El, O) -> + merge(Ns, Os, El, [N|New], Ch, [N|All]); +merge(Ns=[N|_], [O|Os], El, New, Ch, All) + when element(El, N) > element(El, O) -> + merge(Ns, Os, El, New, Ch, [O|All]); +merge([], Os, _El, New, Ch, All) -> + {lists:reverse(All, Os), New, Ch}; +merge(Ns, [], _El, New, Ch, All) -> + {lists:reverse(All, Ns), Ns++New, Ch}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +setup_ttb(TPs, TPids) -> + _R1 = [setup_tps(FTP, []) || {_, FTP} <- TPs], + _R2 = [ttb:p(Pid, dbg_flags(Flags)) || #tpid{pid=Pid, opts=Flags} <- TPids], + [#tpid{pid=_Pid, opts=_Flags}|_] = TPids, + %% io:format("ttb:p(pid(\"~w\", ~w).", [Pid, Flags]), + %% io:format("TTB ~w ~w~n",[R2, R1]), + ok. + +%% Sigh order is important +setup_tps([First=#tpattern{fa={_,'_'}}|Rest], Prev) -> + setup_tp(First), + [setup_tp(TP) || TP <- lists:reverse(Prev)], + setup_tps(Rest, []); +setup_tps([First=#tpattern{fa={F,_}}|Rest], Prev = [#tpattern{fa={F,_}}|_]) -> + setup_tps(Rest, [First|Prev]); +setup_tps([First|Rest], Prev) -> + [setup_tp(TP) || TP <- lists:reverse(Prev)], + setup_tps(Rest, [First]); +setup_tps([], Prev) -> + [setup_tp(TP) || TP <- lists:reverse(Prev)]. + +setup_tp(#tpattern{m=M,fa={F,A}, ms=#match_spec{term=Ms}}) -> + ttb:tpl(M,F,A,Ms). + +dbg_flags(Flags) -> + [dbg_flag(Flag) || Flag <- Flags]. + +dbg_flag(send) -> s; +dbg_flag('receive') -> r; +dbg_flag(functions) -> c; +dbg_flag(on_spawn) -> sos; +dbg_flag(on_link) -> sol; +dbg_flag(on_first_spawn) -> sofs; +dbg_flag(on_first_link) -> sofl; +dbg_flag(events) -> p. + +textformat(Trace) when element(1, Trace) == trace_ts, tuple_size(Trace) >= 4 -> + format_trace(Trace, tuple_size(Trace)-1, element(tuple_size(Trace),Trace)); +textformat(Trace) when element(1, Trace) == drop, tuple_size(Trace) =:= 2 -> + io_lib:format("*** Dropped ~p messages.~n", [element(2,Trace)]); +textformat(Trace) when element(1, Trace) == seq_trace, tuple_size(Trace) >= 3 -> + io_lib:format("*** Seq trace not implmented.~n", []); +textformat(_) -> + "". + +format_trace(Trace, Size, TS0={_,_,MS}) -> + {_,{H,M,S}} = calendar:now_to_local_time(TS0), + TS = io_lib:format("~.2.0w:~.2.0w:~.2.0w:~.6.0w", [H,M,S,MS]), + From = element(2, Trace), + case element(3, Trace) of + 'receive' -> + case element(4, Trace) of + {dbg,ok} -> ""; + Message -> + io_lib:format("~s (~100p) << ~100p ~n", [TS,From,Message]) + end; + 'send' -> + Message = element(4, Trace), + To = element(5, Trace), + io_lib:format("~s (~100p) ~100p ! ~100p ~n", [TS,From,To,Message]); + call -> + case element(4, Trace) of + MFA when Size == 5 -> + Message = element(5, Trace), + io_lib:format("~s (~100p) call ~s (~100p) ~n", [TS,From,ffunc(MFA),Message]); + MFA -> + io_lib:format("~s (~100p) call ~s ~n", [TS,From,ffunc(MFA)]) + end; + return_from -> + MFA = element(4, Trace), + Ret = element(5, Trace), + io_lib:format("~s (~100p) returned from ~s -> ~100p ~n", [TS,From,ffunc(MFA),Ret]); + return_to -> + MFA = element(4, Trace), + io_lib:format("~s (~100p) returning to ~s ~n", [TS,From,ffunc(MFA)]); + spawn when Size == 5 -> + Pid = element(4, Trace), + MFA = element(5, Trace), + io_lib:format("~s (~100p) spawn ~100p as ~s ~n", [TS,From,Pid,ffunc(MFA)]); + Op -> + io_lib:format("~s (~100p) ~100p ~s ~n", [TS,From,Op,ftup(Trace,4,Size)]) + end. + +%%% These f* functions returns non-flat strings + +%% {M,F,[A1, A2, ..., AN]} -> "M:F(A1, A2, ..., AN)" +%% {M,F,A} -> "M:F/A" +ffunc({M,F,Argl}) when is_list(Argl) -> + io_lib:format("~100p:~100p(~s)", [M, F, fargs(Argl)]); +ffunc({M,F,Arity}) -> + io_lib:format("~100p:~100p/~100p", [M,F,Arity]); +ffunc(X) -> io_lib:format("~100p", [X]). + +%% Integer -> "Integer" +%% [A1, A2, ..., AN] -> "A1, A2, ..., AN" +fargs(Arity) when is_integer(Arity) -> integer_to_list(Arity); +fargs([]) -> []; +fargs([A]) -> io_lib:format("~100p", [A]); %% last arg +fargs([A|Args]) -> [io_lib:format("~100p,", [A]) | fargs(Args)]; +fargs(A) -> io_lib:format("~100p", [A]). % last or only arg + +%% {A_1, A_2, ..., A_N} -> "A_Index A_Index+1 ... A_Size" +ftup(Trace, Index, Index) -> + io_lib:format("~100p", [element(Index, Trace)]); +ftup(Trace, Index, Size) -> + [io_lib:format("~100p ", [element(Index, Trace)]) + | ftup(Trace, Index+1, Size)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +write_file(Frame, Filename, TraceOps, MatchSpecs, TPs) -> + FormatMS = fun(#match_spec{name=Id, term=T, func=F}) -> + io_lib:format("[{name,\"~s\"}, {term, ~w}, {func, \"~s\"}]", + [Id, T, F]) + end, + FormatTP = fun({Module, FTPs}) -> + List = format_ftp(FTPs, FormatMS), + io_lib:format("{tp, ~w, [~s]}.~n",[Module, List]) + end, + Str = + ["%%%\n%%% This file is generated by Observer\n", + "%%%\n%%% DO NOT EDIT!\n%%%\n", + [["{ms, ", FormatMS(Ms), "}.\n"] || Ms <- MatchSpecs], + "{traceopts, ", io_lib:format("~w",[TraceOps]) ,"}.\n", + [FormatTP(TP) || TP <- TPs] + ], + case file:write_file(Filename, list_to_binary(Str)) of + ok -> + success; + {error, Reason} -> + FailMsg = file:format_error(Reason), + observer_wx:create_txt_dialog(Frame, FailMsg, "Error", ?wxICON_ERROR) + end. + +format_ftp([#tpattern{fa={F,A}, ms=Ms}], FormatMS) -> + io_lib:format("{~w, ~w, ~s}", [F,A,FormatMS(Ms)]); +format_ftp([#tpattern{fa={F,A}, ms=Ms}|Rest], FormatMS) -> + [io_lib:format("{~w, ~w, ~s},~n ", [F,A,FormatMS(Ms)]), + format_ftp(Rest, FormatMS)]. + +read_settings(Filename, #state{match_specs=Ms0, def_trace_opts=TO0} = State) -> + case file:consult(Filename) of + {ok, Terms} -> + Ms = lists:usort(Ms0 ++ [parse_ms(MsList) || {ms, MsList} <- Terms]), + TOs = lists:usort(TO0 ++ proplists:get_value(traceopts, Terms, [])), + lists:foldl(fun parse_tp/2, + State#state{match_specs=Ms, def_trace_opts=TOs}, + Terms); + {error, _} -> + observer_wx:create_txt_dialog(State#state.panel, "Could not load settings", + "Error", ?wxICON_ERROR), + State + end. + +parse_ms(Opts) -> + Name = proplists:get_value(name, Opts, "TracePattern"), + Term = proplists:get_value(term, Opts, [{'_',[],[ok]}]), + FunStr = proplists:get_value(term, Opts, "fun(_) -> ok end"), + make_ms(Name, Term, FunStr). + +make_ms(Name, Term, FunStr) -> + #match_spec{name=Name, term=Term, str=io_lib:format("~w", Term), func = FunStr}. + +parse_tp({tp, Mod, FAs}, State) -> + Patterns = [#tpattern{m=Mod,fa={F,A}, ms=parse_ms(List)} || + {F,A,List} <- FAs], + do_add_patterns({Mod, Patterns}, State); +parse_tp(_, State) -> + State. diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl new file mode 100644 index 0000000000..bad05ec016 --- /dev/null +++ b/lib/observer/src/observer_traceoptions_wx.erl @@ -0,0 +1,572 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer_traceoptions_wx). + +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). + +-export([process_trace/2, trace_pattern/4]). + +-compile(export_all). + +process_trace(Parent, Default) -> + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Process Options", + [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}]), + Panel = wxPanel:new(Dialog), + MainSz = wxBoxSizer:new(?wxVERTICAL), + PanelSz = wxBoxSizer:new(?wxHORIZONTAL), + LeftSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Tracing options"}]), + RightSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Inheritance options:"}]), + + FuncBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace function call", []), + check_box(FuncBox, lists:member(functions, Default)), + SendBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace send message", []), + check_box(SendBox, lists:member(send, Default)), + RecBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace receive message", []), + check_box(RecBox, lists:member('receive', Default)), + EventBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace process events", []), + check_box(EventBox, lists:member(events, Default)), + + {SpawnBox, SpwnAllRadio, SpwnFirstRadio} = + optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "spawn"), + {LinkBox, LinkAllRadio, LinkFirstRadio} = + optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "link"), + SpawnBool = lists:member(on_spawn, Default) orelse lists:member(on_first_spawn, Default), + LinkBool = lists:member(on_link, Default) orelse lists:member(on_first_link, Default), + check_box(SpawnBox, SpawnBool), + check_box(LinkBox, LinkBool), + enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio]), + enable(LinkBox, [LinkAllRadio, LinkFirstRadio]), + wxRadioButton:setValue(SpwnAllRadio, lists:member(on_spawn, Default)), + wxRadioButton:setValue(SpwnFirstRadio, lists:member(on_first_spawn, Default)), + wxRadioButton:setValue(LinkAllRadio, lists:member(on_link, Default)), + wxRadioButton:setValue(LinkFirstRadio, lists:member(on_first_link, Default)), + + wxSizer:add(LeftSz, FuncBox, []), + wxSizer:add(LeftSz, SendBox, []), + wxSizer:add(LeftSz, RecBox, []), + wxSizer:add(LeftSz, EventBox, []), + wxSizer:add(LeftSz, 150, -1), + + wxSizer:add(PanelSz, LeftSz, [{flag, ?wxEXPAND}]), + wxSizer:add(PanelSz, RightSz,[{flag, ?wxEXPAND}]), + wxPanel:setSizer(Panel, PanelSz), + wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND}, {proportion,1}]), + Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), + wxWindow:setSizerAndFit(Dialog, MainSz), + wxSizer:setSizeHints(MainSz, Dialog), + wxCheckBox:connect(SpawnBox, command_checkbox_clicked, + [{callback, fun(#wx{event=#wxCommand{}},_) -> + enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio]) + end}]), + wxCheckBox:connect(LinkBox, command_checkbox_clicked, + [{callback, fun(#wx{event=#wxCommand{}},_) -> + enable(LinkBox, [LinkAllRadio, LinkFirstRadio]) + end}]), + + Res = case wxDialog:showModal(Dialog) of + ?wxID_OK -> + All = [{SendBox, send}, {RecBox, 'receive'}, + {FuncBox, functions}, {EventBox, events}, + {{SpawnBox, SpwnAllRadio}, on_spawn}, + {{SpawnBox,SpwnFirstRadio}, on_first_spawn}, + {{LinkBox, LinkAllRadio}, on_link}, + {{LinkBox, LinkFirstRadio}, on_first_link}], + Check = fun({Box, Radio}) -> + wxCheckBox:getValue(Box) andalso wxRadioButton:getValue(Radio); + (Box) -> + wxCheckBox:getValue(Box) + end, + Opts = [Id || {Tick, Id} <- All, Check(Tick)], + {ok, lists:reverse(Opts)}; + ?wxID_CANCEL -> + cancel + end, + wxDialog:destroy(Dialog), + Res. + +trace_pattern(ParentPid, Parent, Node, MatchSpecs) -> + try + Module = module_selector(Parent, Node), + MFAs = function_selector(Parent, Node, Module), + MatchSpec = select_matchspec(ParentPid, Parent, MatchSpecs), + {Module, [#tpattern{m=M,fa={F,A},ms=MatchSpec} || {M,F,A} <- MFAs]} + catch cancel -> cancel + end. + +module_selector(Parent, Node) -> + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module", + [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, + {size, {400, 400}}]), + Panel = wxPanel:new(Dialog), + PanelSz = wxBoxSizer:new(?wxVERTICAL), + MainSz = wxBoxSizer:new(?wxVERTICAL), + + TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY), + ListBox = wxListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_SINGLE}]), + wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]), + wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxPanel:setSizer(Panel, PanelSz), + wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 1}]), + Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 0}]), + wxWindow:setSizer(Dialog, MainSz), + OkId = wxDialog:getAffirmativeId(Dialog), + OkButt = wxWindow:findWindowById(OkId), + wxWindow:disable(OkButt), + wxWindow:setFocus(TxtCtrl), + %% init data + Modules = get_modules(Node), + AllModules = [{atom_to_list(X), X} || X <- Modules], + filter_listbox_data("", AllModules, ListBox), + wxTextCtrl:connect(TxtCtrl, command_text_updated, + [{callback, fun(#wx{event=#wxCommand{cmdString=Input}}, _) -> + filter_listbox_data(Input, AllModules, ListBox) + end}]), + wxListBox:connect(ListBox, command_listbox_doubleclicked, + [{callback, fun(_, _) -> wxDialog:endModal(Dialog, ?wxID_OK) end}]), + wxListBox:connect(ListBox, command_listbox_selected, + [{callback, fun(#wx{event=#wxCommand{commandInt=Id}}, _) -> + Id >= 0 andalso wxWindow:enable(OkButt) + end}]), + + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + SelId = wxListBox:getSelection(ListBox), + case SelId >= 0 of + true -> + Module = wxListBox:getClientData(ListBox, SelId), + wxDialog:destroy(Dialog), + Module; + false -> + wxDialog:destroy(Dialog), + throw(cancel) + end; + ?wxID_CANCEL -> + wxDialog:destroy(Dialog), + throw(cancel) + end. + +function_selector(Parent, Node, Module) -> + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions", + [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, + {size, {400, 400}}]), + + Panel = wxPanel:new(Dialog), + PanelSz = wxBoxSizer:new(?wxVERTICAL), + MainSz = wxBoxSizer:new(?wxVERTICAL), + + TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY), + ListBox = wxCheckListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_EXTENDED}]), + wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]), + wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]), + SelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Check Visible"}]), + DeSelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Uncheck Visible"}]), + ButtonSz = wxBoxSizer:new(?wxHORIZONTAL), + [wxSizer:add(ButtonSz, Button, []) || Button <- [SelAllBtn, DeSelAllBtn]], + wxSizer:add(PanelSz, ButtonSz, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 0}]), + wxPanel:setSizer(Panel, PanelSz), + wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 1}]), + + Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 0}]), + wxWindow:setSizer(Dialog, MainSz), + wxWindow:setFocus(TxtCtrl), + %% Init + Functions = observer_wx:try_rpc(Node, Module, module_info, [functions]), + Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions, + not(erl_internal:guard_bif(Name, Arity))]), + ParsedChoices = parse_function_names(Choices), + filter_listbox_data("", ParsedChoices, ListBox, false), + %% Setup Event handling + wxTextCtrl:connect(TxtCtrl, command_text_updated, + [{callback, + fun(#wx{event=#wxCommand{cmdString=Input}}, _) -> + filter_listbox_data(Input, ParsedChoices, ListBox, false) + end}]), + Self = self(), + + %% Sigh clientdata in checklistbox crashes on windows, wx-bug I presume. + %% Don't have time to investigate now, workaround file bug report later + GetClientData = fun(LB, N) -> + String = wxListBox:getString(LB, N), + {_, Data} = lists:keyfind(String, 1, ParsedChoices), + Data + end, + wxCheckListBox:connect(ListBox, command_checklistbox_toggled, + [{callback, + fun(#wx{event=#wxCommand{commandInt=N}}, _) -> + Self ! {ListBox, wxCheckListBox:isChecked(ListBox, N), + GetClientData(ListBox, N)} + end}]), + Check = fun(Id, Bool) -> + wxCheckListBox:check(ListBox, Id, [{check, Bool}]), + Self ! {ListBox, Bool, GetClientData(ListBox, Id)} + end, + wxButton:connect(SelAllBtn, command_button_clicked, + [{callback, fun(#wx{}, _) -> + Count = wxListBox:getCount(ListBox), + [Check(SelId, true) || + SelId <- lists:seq(0, Count-1), + not wxCheckListBox:isChecked(ListBox, SelId)] + end}]), + wxButton:connect(DeSelAllBtn, command_button_clicked, + [{callback, fun(#wx{}, _) -> + Count = wxListBox:getCount(ListBox), + [Check(SelId, false) || + SelId <- lists:seq(0, Count-1), + wxCheckListBox:isChecked(ListBox, SelId)] + end}]), + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + wxDialog:destroy(Dialog), + case get_checked_funcs(ListBox, []) of + [] -> [{Module, '_', '_'}]; + FAs -> + [{Module, F, A} || {F,A} <- FAs] + end; + ?wxID_CANCEL -> + wxDialog:destroy(Dialog), + throw(cancel) + end. + +get_checked_funcs(ListBox, Acc) -> + receive + {ListBox, true, FA} -> + get_checked_funcs(ListBox, [FA|lists:delete(FA,Acc)]); + {ListBox, false, FA} -> + get_checked_funcs(ListBox, lists:delete(FA,Acc)) + after 0 -> + lists:reverse(Acc) + end. + +select_matchspec(Pid, Parent, MatchSpecs) -> + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications", + [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, + {size, {400, 400}}]), + + Panel = wxPanel:new(Dialog), + PanelSz = wxBoxSizer:new(?wxVERTICAL), + MainSz = wxBoxSizer:new(?wxVERTICAL), + TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]), + BtnSz = wxBoxSizer:new(?wxHORIZONTAL), + SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]), + + TextCtrl = create_styled_txtctrl(Panel), + wxSizer:add(TxtSz, TextCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]), + + AddMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "New"}]), + EditMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Edit"}]), + DelMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Delete"}]), + wxSizer:add(BtnSz, AddMsBtn), + wxSizer:add(BtnSz, EditMsBtn), + wxSizer:add(BtnSz, DelMsBtn), + + ListBox = wxListBox:new(Panel, ?wxID_ANY, []), + wxSizer:add(SavedSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxSizer:add(PanelSz, TxtSz, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxSizer:add(PanelSz, BtnSz), + wxSizer:add(PanelSz, SavedSz, [{flag, ?wxEXPAND}, {proportion, 1}]), + + wxWindow:setSizer(Panel, PanelSz), + wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 1}]), + Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}, {proportion, 0}]), + wxWindow:setSizer(Dialog, MainSz), + OkId = wxDialog:getAffirmativeId(Dialog), + OkButt = wxWindow:findWindowById(OkId), + wxWindow:disable(OkButt), + wxWindow:disable(EditMsBtn), + wxWindow:disable(DelMsBtn), + + Choices = ms_names(MatchSpecs), + filter_listbox_data("", Choices, ListBox), + + Add = fun(_,_) -> + case edit_ms(TextCtrl, new, Parent) of + Ms = #match_spec{} -> add_and_select(-1, Ms, ListBox); + Else -> Else + end + end, + Edit = fun(_,_) -> + SelId = wxListBox:getSelection(ListBox), + case SelId >= 0 of + true -> + #match_spec{name=Name} = wxListBox:getClientData(ListBox,SelId), + case edit_ms(TextCtrl, Name, Parent) of + Ms = #match_spec{} -> add_and_select(SelId, Ms, ListBox); + Else -> Else + end; + false -> + ok + end + end, + Del = fun(_,_) -> + SelId = wxListBox:getSelection(ListBox), + case SelId >= 0 of + true -> + wxListBox:delete(ListBox, SelId); + false -> + ok + end + end, + Sel = fun(#wx{event=#wxCommand{commandInt=Id}}, _) -> + case Id >= 0 of + true -> + wxWindow:enable(OkButt), + wxWindow:enable(EditMsBtn), + wxWindow:enable(DelMsBtn), + #match_spec{func=Str} = wxListBox:getClientData(ListBox,Id), + wxStyledTextCtrl:setText(TextCtrl, Str); + false -> + try + wxWindow:disable(OkButt), + wxWindow:disable(EditMsBtn), + wxWindow:disable(DelMsBtn) + catch _:_ -> ok + end + end + end, + wxButton:connect(AddMsBtn, command_button_clicked, [{callback,Add}]), + wxButton:connect(EditMsBtn, command_button_clicked, [{callback,Edit}]), + wxButton:connect(DelMsBtn, command_button_clicked, [{callback,Del}]), + wxListBox:connect(ListBox, command_listbox_selected, [{callback, Sel}]), + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + SelId = wxListBox:getSelection(ListBox), + Count = wxListBox:getCount(ListBox), + MSs = [wxListBox:getClientData(ListBox, Id) || + Id <- lists:seq(0, Count-1)], + Pid ! {update_ms, MSs}, + MS = lists:nth(SelId+1, MSs), + wxDialog:destroy(Dialog), + MS; + ?wxID_CANCEL -> + wxDialog:destroy(Dialog), + throw(cancel) + end. + +edit_ms(TextCtrl, Label0, Parent) -> + Str = ensure_last_is_dot(wxStyledTextCtrl:getText(TextCtrl)), + try + MatchSpec = ms_from_string(Str), + Label = case Label0 == new of + true -> get_label(Parent); + _ -> Label0 + end, + #match_spec{name=Label, term=MatchSpec, + str=io_lib:format("~w",[MatchSpec]), + func=Str} + catch + throw:cancel -> + ok; + throw:Error -> + observer_wx:create_txt_dialog(Parent, Error, "Error", ?wxICON_ERROR), + ok + end. + +get_label(Frame) -> + Dialog = wxTextEntryDialog:new(Frame, "Enter alias: "), + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + wxTextEntryDialog:getValue(Dialog); + ?wxID_CANCEL -> + throw(cancel) + end. + +ms_from_string(Str) -> + try + Tokens = case erl_scan:string(Str) of + {ok, Ts, _} -> Ts; + {error, {SLine, SMod, SError}, _} -> + throw(io_lib:format("~w: ~s", [SLine,SMod:format_error(SError)])) + end, + Exprs = case erl_parse:parse_exprs(Tokens) of + {ok, T} -> T; + {error, {PLine, PMod, PError}} -> + throw(io_lib:format("~w: ~s", [PLine,PMod:format_error(PError)])) + end, + Term = case Exprs of + [{'fun', _, {clauses, Clauses}}|_] -> + case ms_transform:transform_from_shell(dbg,Clauses,orddict:new()) of + {error, [{_,[{MSLine,Mod,MSInfo}]}],_} -> + throw(io_lib:format("~w: ~p", [MSLine,Mod:format_error(MSInfo)])); + {error, _} -> + throw("Could not convert fun() to match spec"); + Ms -> + Ms + end; + [Expr|_] -> + erl_parse:normalise(Expr) + end, + case erlang:match_spec_test([], Term, trace) of + {ok, _, _, _} -> Term; + {error, List} -> throw([[Error, $\n] || {_, Error} <- List]) + end + catch error:_Reason -> + %% io:format("Bad term: ~s~n ~p in ~p~n", [Str, _Reason, erlang:get_stacktrace()]), + throw("Invalid term") + end. + +add_and_select(Id, MS0, ListBox) -> + [{Str,User}] = ms_names([MS0]), + Sel = case Id >= 0 of + true -> + wxListBox:setString(ListBox, Id, Str), + wxListBox:setClientData(ListBox, Id, User), + Id; + false -> + wxListBox:append(ListBox, Str, User) + end, + wxListBox:setSelection(ListBox, Sel). + +filter_listbox_data(Input, Data, ListBox) -> + filter_listbox_data(Input, Data, ListBox, true). + +filter_listbox_data(Input, Data, ListBox, AddClientData) -> + FilteredData = [X || X = {Str, _} <- Data, re:run(Str, Input) =/= nomatch], + wxListBox:clear(ListBox), + wxListBox:appendStrings(ListBox, [Str || {Str,_} <- FilteredData]), + AddClientData andalso + wx:foldl(fun({_, Term}, N) -> + wxListBox:setClientData(ListBox, N, Term), + N+1 + end, 0, FilteredData), + FilteredData. + +get_modules(Node) -> + lists:sort([Module || {Module, _} <- observer_wx:try_rpc(Node, code, all_loaded, [])]). + +optionpage_top_right(Panel, TopRightSz, Options, Text) -> + Sizer = wxBoxSizer:new(?wxVERTICAL), + ChkBox = wxCheckBox:new(Panel, ?wxID_ANY, "Inherit on " ++ Text, []), + RadioSz = wxBoxSizer:new(?wxVERTICAL), + Radio1 = wxRadioButton:new(Panel, ?wxID_ANY, "All " ++ Text, [{style, ?wxRB_GROUP}]), + Radio2 = wxRadioButton:new(Panel, ?wxID_ANY, "First " ++ Text ++ " only", []), + wxSizer:add(Sizer, ChkBox, []), + wxSizer:add(RadioSz, Radio1, []), + wxSizer:add(RadioSz, Radio2, []), + wxSizer:add(Sizer, RadioSz, [{flag, ?wxLEFT},{border, 20}]), + wxSizer:add(TopRightSz, Sizer, Options), + {ChkBox, Radio1, Radio2}. + + +create_styled_txtctrl(Parent) -> + FixedFont = observer_wx:get_attrib({font, fixed}), + Ed = wxStyledTextCtrl:new(Parent), + wxStyledTextCtrl:styleClearAll(Ed), + wxStyledTextCtrl:styleSetFont(Ed, ?wxSTC_STYLE_DEFAULT, FixedFont), + wxStyledTextCtrl:setLexer(Ed, ?wxSTC_LEX_ERLANG), + wxStyledTextCtrl:setMarginType(Ed, 1, ?wxSTC_MARGIN_NUMBER), + wxStyledTextCtrl:setSelectionMode(Ed, ?wxSTC_SEL_LINES), + wxStyledTextCtrl:setUseHorizontalScrollBar(Ed, false), + + Styles = [{?wxSTC_ERLANG_DEFAULT, {0,0,0}}, + {?wxSTC_ERLANG_COMMENT, {160,53,35}}, + {?wxSTC_ERLANG_VARIABLE, {150,100,40}}, + {?wxSTC_ERLANG_NUMBER, {5,5,100}}, + {?wxSTC_ERLANG_KEYWORD, {130,40,172}}, + {?wxSTC_ERLANG_STRING, {170,45,132}}, + {?wxSTC_ERLANG_OPERATOR, {30,0,0}}, + {?wxSTC_ERLANG_ATOM, {0,0,0}}, + {?wxSTC_ERLANG_FUNCTION_NAME, {64,102,244}}, + {?wxSTC_ERLANG_CHARACTER,{236,155,172}}, + {?wxSTC_ERLANG_MACRO, {40,144,170}}, + {?wxSTC_ERLANG_RECORD, {40,100,20}}, + {?wxSTC_ERLANG_SEPARATOR,{0,0,0}}, + {?wxSTC_ERLANG_NODE_NAME,{0,0,0}}], + SetStyle = fun({Style, Color}) -> + wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont), + wxStyledTextCtrl:styleSetForeground(Ed, Style, Color) + end, + [SetStyle(Style) || Style <- Styles], + wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()), + Ed. + + +keyWords() -> + L = ["after","begin","case","try","cond","catch","andalso","orelse", + "end","fun","if","let","of","query","receive","when","bnot","not", + "div","rem","band","and","bor","bxor","bsl","bsr","or","xor"], + lists:flatten([K ++ " " || K <- L] ++ [0]). + + +enable(CheckBox, Radio) -> + case wxCheckBox:isChecked(CheckBox) of + false -> + [wxWindow:disable(R) || R <- Radio]; + true -> + [wxWindow:enable(R) || R <- Radio] + end. + + +check_box(ChkBox, Bool) -> + case Bool of + true -> + wxCheckBox:set3StateValue(ChkBox, ?wxCHK_CHECKED); + false -> + ignore + end. + +parse_function_names(Choices) -> + StrList = [{atom_to_list(Name) ++ "/" ++ integer_to_list(Arity), Term} + || Term = {Name, Arity} <- Choices], + parse_function_names(StrList, []). + +parse_function_names([], Acc) -> + lists:reverse(Acc); +parse_function_names([{H, Term}|T], Acc) -> + IsFun = re:run(H, ".*-fun-\\d*?-"), + IsLc = re:run(H, ".*-lc\\$\\^\\d*?/\\d*?-\\d*?-"), + IsLbc = re:run(H, ".*-lbc\\$\\^\\d*?/\\d*?-\\d*?-"), + Parsed = + if IsFun =/= nomatch -> "Fun: " ++ H; + IsLc =/= nomatch -> "List comprehension: " ++ H; + IsLbc =/= nomatch -> "Bit comprehension: " ++ H; + true -> + H + end, + parse_function_names(T, [{Parsed, Term} | Acc]). + +ms_names(MatchSpecList) -> + MsOrAlias = fun(#match_spec{name = A, str = M}) -> + case A of + "" -> M; + _ -> A ++ " " ++ M + end + end, + [{MsOrAlias(X), X} || X <- MatchSpecList]. + +ensure_last_is_dot([]) -> + "."; +ensure_last_is_dot(String) -> + case lists:last(String) =:= $. of + true -> + String; + false -> + String ++ "." + end. diff --git a/lib/observer/src/observer_tv.hrl b/lib/observer/src/observer_tv.hrl new file mode 100644 index 0000000000..05e4f928d0 --- /dev/null +++ b/lib/observer/src/observer_tv.hrl @@ -0,0 +1,34 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-record(tab, {name, + id = ignore, + size, + memory=0, %% In bytes + owner, + reg_name, + protection = public, + type=set, + keypos=1, + heir=none, + compressed=false, + fixed=false, + %% Mnesia Info + storage, + index + }). diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl new file mode 100644 index 0000000000..7b5cdb44b9 --- /dev/null +++ b/lib/observer/src/observer_tv_table.erl @@ -0,0 +1,801 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(observer_tv_table). + +-export([start_link/2]). + +%% wx_object callbacks +-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, + handle_event/2, handle_sync_event/3, handle_cast/2]). + +-export([get_table/3]). + +-include("observer_defs.hrl"). +-import(observer_lib, [to_str/1]). + +-behaviour(wx_object). +-include_lib("wx/include/wx.hrl"). +-include("observer_tv.hrl"). + +-define(ID_TABLE_INFO, 400). +-define(ID_REFRESH, 401). +-define(ID_REFRESH_INTERVAL, 402). +-define(ID_EDIT, 403). +-define(ID_DELETE, 404). +-define(ID_SEARCH, 405). + +-define(SEARCH_ENTRY, 420). +-define(GOTO_ENTRY, 421). + +-define(DEFAULT_COL_WIDTH, 150). + +-record(state, + { + parent, + frame, + grid, + status, + sizer, + search, + selected, + node=node(), + columns, + pid, + source, + tab, + attrs, + timer + }). + +-record(opt, + { + sort_key=2, + sort_incr=true + }). + +-record(search, + {enable=true, % Subwindow is enabled + win, % Sash Sub window obj + name, % name + + search, % Search input ctrl + goto, % Goto input ctrl + radio, % Radio buttons + + find % Search string + }). + +-record(find, {start, % start pos + strlen, % Found + found % false + }). + +start_link(Parent, Opts) -> + wx_object:start_link(?MODULE, [Parent, Opts], []). + +init([Parent, Opts]) -> + Source = proplists:get_value(type, Opts), + Table = proplists:get_value(table, Opts), + Node = proplists:get_value(node, Opts), + Title0 = atom_to_list(Table#tab.name) ++ " @ " ++ atom_to_list(Node), + Title = case Source of + ets -> "TV Ets: " ++ Title0; + mnesia -> "TV Mnesia: " ++ Title0 + end, + Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 300}}]), + IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), + Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), + wxFrame:setIcon(Frame, Icon), + wxIcon:destroy(Icon), + MenuBar = wxMenuBar:new(), + create_menus(MenuBar), + wxFrame:setMenuBar(Frame, MenuBar), + %% wxFrame:setAcceleratorTable(Frame, AccelTable), + wxMenu:connect(Frame, command_menu_selected), + + StatusBar = wxFrame:createStatusBar(Frame, []), + try + TabId = table_id(Table), + ColumnNames = column_names(Node, Source, TabId), + KeyPos = key_pos(Node, Source, TabId), + + Attrs = observer_lib:create_attrs(), + + Self = self(), + Holder = spawn_link(fun() -> + init_table_holder(Self, Table, Source, + length(ColumnNames), Node, Attrs) + end), + + Panel = wxPanel:new(Frame), + Sizer = wxBoxSizer:new(?wxVERTICAL), + Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, + Grid = wxListCtrl:new(Panel, [{style, Style}, + {onGetItemText, + fun(_, Item,Col) -> get_row(Holder, Item, Col+1) end}, + {onGetItemAttr, + fun(_, Item) -> get_attr(Holder, Item) end} + ]), + wxListCtrl:connect(Grid, command_list_item_activated), + wxListCtrl:connect(Grid, command_list_item_selected), + wxListCtrl:connect(Grid, command_list_col_click), + wxListCtrl:connect(Grid, size, [{skip, true}]), + wxWindow:setFocus(Grid), + + Search = search_area(Panel), + wxSizer:add(Sizer, Grid, + [{flag, ?wxEXPAND bor ?wxALL}, {proportion, 1}, {border, 5}]), + wxSizer:add(Sizer, Search#search.win, + [{flag,?wxEXPAND bor ?wxLEFT bor ?wxRIGHT bor + ?wxRESERVE_SPACE_EVEN_IF_HIDDEN}, + {border, 5}]), + wxWindow:setSizer(Panel, Sizer), + wxSizer:hide(Sizer, Search#search.win), + + Cols = add_columns(Grid, 0, ColumnNames), + wxFrame:show(Frame), + {Panel, #state{frame=Frame, grid=Grid, status=StatusBar, search=Search, + sizer = Sizer, + parent=Parent, columns=Cols, + pid=Holder, source=Source, tab=Table#tab{keypos=KeyPos}, + attrs=Attrs}} + catch node_or_table_down -> + wxFrame:destroy(Frame), + stop + end. + +add_columns(Grid, Start, ColumnNames) -> + Li = wxListItem:new(), + AddListEntry = fun(Name, Col) -> + wxListItem:setText(Li, to_str(Name)), + wxListItem:setAlign(Li, ?wxLIST_FORMAT_LEFT), + wxListCtrl:insertColumn(Grid, Col, Li), + wxListCtrl:setColumnWidth(Grid, Col, ?DEFAULT_COL_WIDTH), + Col + 1 + end, + Cols = lists:foldl(AddListEntry, Start, ColumnNames), + wxListItem:destroy(Li), + Cols. + +create_menus(MB) -> + File = wxMenu:new(), + wxMenu:append(File, ?ID_TABLE_INFO, "Table Information\tCtrl-I"), + wxMenu:append(File, ?wxID_CLOSE, "Close"), + wxMenuBar:append(MB, File, "File"), + Edit = wxMenu:new(), + wxMenu:append(Edit, ?ID_EDIT, "Edit Object"), + wxMenu:append(Edit, ?ID_DELETE, "Delete Object\tCtrl-D"), + wxMenu:appendSeparator(Edit), + wxMenu:append(Edit, ?ID_SEARCH, "Search\tCtrl-S"), + wxMenu:appendSeparator(Edit), + wxMenu:append(Edit, ?ID_REFRESH, "Refresh\tCtrl-R"), + wxMenu:append(Edit, ?ID_REFRESH_INTERVAL, "Refresh interval..."), + wxMenuBar:append(MB, Edit, "Edit"), + Help = wxMenu:new(), + wxMenu:append(Help, ?wxID_HELP, "Help"), + wxMenuBar:append(MB, Help, "Help"), + ok. + +search_area(Parent) -> + HSz = wxBoxSizer:new(?wxHORIZONTAL), + wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"), + [{flag,?wxALIGN_CENTER_VERTICAL}]), + TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), + wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]), + Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"), + wxRadioButton:setValue(Nbtn, true), + wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + Pbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Previous"), + wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"), + wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]), + wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Entry:"), + [{flag,?wxALIGN_CENTER_VERTICAL}]), + TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), + wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]), + wxTextCtrl:connect(TC1, command_text_updated), + wxTextCtrl:connect(TC1, command_text_enter), + wxTextCtrl:connect(TC1, kill_focus), + wxTextCtrl:connect(TC2, command_text_enter), + wxWindow:connect(Parent, command_button_clicked), + + #search{name='Search Area', win=HSz, + search=TC1,goto=TC2,radio={Nbtn,Pbtn,Cbtn}}. + +edit(Index, #state{pid=Pid, frame=Frame}) -> + Str = get_row(Pid, Index, all), + Dialog = wxTextEntryDialog:new(Frame, "Edit object:", [{value, Str}]), + case wxTextEntryDialog:showModal(Dialog) of + ?wxID_OK -> + New = wxTextEntryDialog:getValue(Dialog), + wxTextEntryDialog:destroy(Dialog), + case Str =:= New of + true -> ok; + false -> + complete_edit(Index, New, Pid) + end; + ?wxID_CANCEL -> + wxTextEntryDialog:destroy(Dialog) + end. + +complete_edit(Row, New0, Pid) -> + New = case lists:reverse(New0) of + [$.|_] -> New0; + _ -> New0 ++ "." + end, + try + {ok, Tokens, _} = erl_scan:string(New), + {ok, Term} = erl_parse:parse_term(Tokens), + Pid ! {edit, Row, Term} + catch _:{badmatch, {error, {_, _, Err}}} -> + self() ! {error, ["Parse error: ", Err]}; + _Err -> + self() ! {error, ["Syntax error in: ", New]} + end. + +handle_event(#wx{id=?ID_REFRESH},State = #state{pid=Pid}) -> + Pid ! refresh, + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}}, + State = #state{pid=Pid}) -> + Pid ! {sort, Col+1}, + {noreply, State}; + +handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) -> + wx:batch(fun() -> + Cols = wxListCtrl:getColumnCount(Grid), + Last = lists:foldl(fun(I, Last) -> + Last - wxListCtrl:getColumnWidth(Grid, I) + end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)), + Size = max(?DEFAULT_COL_WIDTH, Last), + wxListCtrl:setColumnWidth(Grid, Cols-1, Size) + end), + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_item_selected, itemIndex=Index}}, + State = #state{pid=Pid, grid=Grid, status=StatusBar}) -> + N = wxListCtrl:getItemCount(Grid), + Str = get_row(Pid, Index, all), + wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w: ~s",[N, Str])), + {noreply, State#state{selected=Index}}; + +handle_event(#wx{event=#wxList{type=command_list_item_activated, itemIndex=Index}}, + State) -> + edit(Index, State), + {noreply, State}; + +handle_event(#wx{id=?ID_EDIT}, State = #state{selected=undefined}) -> + {noreply, State}; +handle_event(#wx{id=?ID_EDIT}, State = #state{selected=Index}) -> + edit(Index, State), + {noreply, State}; + +handle_event(#wx{id=?ID_DELETE}, State = #state{selected=undefined}) -> + {noreply, State}; +handle_event(#wx{id=?ID_DELETE}, + State = #state{pid=Pid, status=StatusBar, selected=Index}) -> + Str = get_row(Pid, Index, all), + Pid ! {delete, Index}, + wxStatusBar:setStatusText(StatusBar, io_lib:format("Deleted object: ~s",[Str])), + {noreply, State}; + +handle_event(#wx{id=?wxID_CLOSE}, State) -> + {stop, normal, State}; + +handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) -> + Parent ! Help, + {noreply, State}; + +handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}}, + State = #state{grid=Grid}) -> + try + Row0 = list_to_integer(Str), + Row1 = min(0, Row0), + Row = max(wxListCtrl:getItemCount(Grid)-1,Row1), + wxListCtrl:ensureVisible(Grid, Row), + ok + catch _:_ -> ok + end, + {noreply, State}; + +%% Search functionality +handle_event(#wx{id=?ID_SEARCH}, + State = #state{sizer=Sz, search=Search}) -> + wxSizer:show(Sz, Search#search.win), + wxWindow:setFocus(Search#search.search), + wxSizer:layout(Sz), + {noreply, State}; +handle_event(#wx{id=?SEARCH_ENTRY, event=#wxFocus{}}, + State = #state{search=Search, pid=Pid}) -> + Pid ! {mark_search_hit, false}, + {noreply, State#state{search=Search#search{find=undefined}}}; +handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=""}}, + State = #state{search=Search, pid=Pid}) -> + Pid ! {mark_search_hit, false}, + {noreply, State#state{search=Search#search{find=undefined}}}; +handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{type=command_text_enter,cmdString=Str}}, + State = #state{grid=Grid, pid=Pid, status=SB, + search=Search=#search{radio={Next0, _, Case0}, + find=Find}}) + when Find =/= undefined -> + Dir = wxRadioButton:getValue(Next0) xor wx_misc:getKeyState(?WXK_SHIFT), + Case = wxCheckBox:getValue(Case0), + Pos = if Find#find.found, Dir -> %% Forward Continuation + Find#find.start+1; + Find#find.found -> %% Backward Continuation + Find#find.start-1; + Dir -> %% Forward wrap + 0; + true -> %% Backward wrap + wxListCtrl:getItemCount(Grid)-1 + end, + Pid ! {mark_search_hit, false}, + case search(Pid, Str, Pos, Dir, Case) of + false -> + wxStatusBar:setStatusText(SB, "Not found"), + Pid ! {mark_search_hit, Find#find.start}, + wxListCtrl:refreshItem(Grid, Find#find.start), + {noreply, State#state{search=Search#search{find=#find{found=false}}}}; + Row -> + wxListCtrl:ensureVisible(Grid, Row), + wxListCtrl:refreshItem(Grid, Row), + Status = "Found: (Hit Enter for next, Shift-Enter for previous)", + wxStatusBar:setStatusText(SB, Status), + {noreply, State#state{search=Search#search{find=#find{start=Row, found=true}}}} + end; +handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=Str}}, + State = #state{grid=Grid, pid=Pid, status=SB, + search=Search=#search{radio={Next0, _, Case0}, + find=Find}}) -> + try + Dir = wxRadioButton:getValue(Next0), + Case = wxCheckBox:getValue(Case0), + Start = case Dir of + true -> 0; + false -> wxListCtrl:getItemCount(Grid)-1 + end, + Cont = case Find of + undefined -> + #find{start=Start, strlen=length(Str)}; + #find{strlen=Old} when Old < length(Str) -> + Find#find{start=Start, strlen=length(Str)}; + _ -> + Find#find{strlen=length(Str)} + end, + + Pid ! {mark_search_hit, false}, + case search(Pid, Str, Cont#find.start, Dir, Case) of + false -> + wxStatusBar:setStatusText(SB, "Not found"), + {noreply, State}; + Row -> + wxListCtrl:ensureVisible(Grid, Row), + wxListCtrl:refreshItem(Grid, Row), + Status = "Found: (Hit Enter for next, Shift-Enter for previous)", + wxStatusBar:setStatusText(SB, Status), + {noreply, State#state{search=Search#search{find=#find{start=Row, found=true}}}} + end + catch _:_ -> {noreply, State} + end; + +handle_event(#wx{id=?ID_TABLE_INFO}, + State = #state{frame=Frame, node=Node, source=Source, tab=Table}) -> + observer_tv_wx:display_table_info(Frame, Node, Source, Table), + {noreply, State}; + +handle_event(#wx{id=?ID_REFRESH_INTERVAL}, + State = #state{grid=Grid, timer=Timer0}) -> + Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60), + {noreply, State#state{timer=Timer}}; + +handle_event(Event, State) -> + io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), + {noreply, State}. + +handle_sync_event(Event, _Obj, _State) -> + io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]), + ok. + +handle_call(Event, From, State) -> + io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]), + {noreply, State}. + +handle_cast(Event, State) -> + io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]), + {noreply, State}. + +handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) -> + wxListCtrl:setItemCount(Grid, N), + wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])), + {noreply, State}; +handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) -> + Cols = add_columns(Grid, Cols0, New), + {noreply, State#state{columns=Cols}}; +handle_info({refresh, Min, Max}, State = #state{grid=Grid}) -> + wxListCtrl:refreshItems(Grid, Min, Max), + {noreply, State}; +handle_info({error, Error}, State = #state{frame=Frame}) -> + Dlg = wxMessageDialog:new(Frame, Error), + wxMessageDialog:showModal(Dlg), + wxMessageDialog:destroy(Dlg), + {noreply, State}; + +handle_info(Event, State) -> + io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]), + {noreply, State}. + +terminate(_Event, #state{pid=Pid, attrs=Attrs}) -> + %% ListItemAttr are not auto deleted + #attrs{odd=Odd, deleted=D, changed=Ch, searched=S} = Attrs, + wxListItemAttr:destroy(Odd), + wxListItemAttr:destroy(D), + wxListItemAttr:destroy(Ch), + wxListItemAttr:destroy(S), + unlink(Pid), + exit(Pid, window_closed), + ok. + +code_change(_, _, State) -> + State. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Table holder needs to be in a separate process otherwise +%% the callback get_row/3 may deadlock if the process do +%% wx calls when callback is invoked. +get_row(Table, Item, Column) -> + Ref = erlang:monitor(process, Table), + Table ! {get_row, self(), Item, Column}, + receive + {'DOWN', Ref, _, _, _} -> ""; + {Table, Res} -> + erlang:demonitor(Ref), + Res + end. + +get_attr(Table, Item) -> + Ref = erlang:monitor(process, Table), + Table ! {get_attr, self(), Item}, + receive + {'DOWN', Ref, _, _, _} -> ""; + {Table, Res} -> + erlang:demonitor(Ref), + Res + end. + +search(Table, Str, Row, Dir, Case) -> + Ref = erlang:monitor(process, Table), + Table ! {search, [Str, Row, Dir, Case]}, + receive + {'DOWN', Ref, _, _, _} -> ""; + {Table, Res} -> + erlang:demonitor(Ref), + Res + end. + +-record(holder, {node, parent, pid, + table=[], n=0, columns, + temp=[], + search, + source, tabid, + sort, + key, + type, + attrs + }). + +init_table_holder(Parent, Table, MnesiaOrEts, Cols, Node, Attrs) -> + TabId = case Table#tab.id of + ignore -> Table#tab.name; + Id -> Id + end, + self() ! refresh, + table_holder(#holder{node=Node, parent=Parent, + source=MnesiaOrEts, tabid=TabId, columns=Cols, + sort=#opt{sort_key=Table#tab.keypos, sort_incr=true}, + type=Table#tab.type, key=Table#tab.keypos, + attrs=Attrs}). + +table_holder(S0 = #holder{parent=Parent, pid=Pid, table=Table}) -> + receive + {get_attr, From, Row} -> + get_attr(From, Row, S0), + table_holder(S0); + {get_row, From, Row, Col} -> + get_row(From, Row, Col, Table), + table_holder(S0); + {Pid, Data} -> + S1 = handle_new_data_chunk(Data, S0), + table_holder(S1); + {sort, Col} -> + table_holder(sort(Col, S0)); + {search, Data} -> + table_holder(search(Data, S0)); + {mark_search_hit, Row} -> + Old = S0#holder.search, + is_integer(Old) andalso (Parent ! {refresh, Old, Old}), + table_holder(S0#holder{search=Row}); + refresh when is_pid(Pid) -> + %% Already getting the table... + %% io:format("ignoring refresh", []), + table_holder(S0); + refresh -> + GetTab = rpc:call(S0#holder.node, ?MODULE, get_table, + [self(), S0#holder.tabid, S0#holder.source]), + table_holder(S0#holder{pid=GetTab}); + {delete, Row} -> + delete_row(Row, S0), + table_holder(S0); + {edit, Row, Term} -> + edit_row(Row, Term, S0), + table_holder(S0); + What -> + io:format("Table holder got ~p~n",[What]), + table_holder(S0) + end. + +handle_new_data_chunk(Data, S0 = #holder{columns=Cols, parent=Parent}) -> + S1 = #holder{columns=NewCols} = handle_new_data_chunk2(Data, S0), + case NewCols =:= Cols of + true -> S1; + false -> + Parent ! {new_cols, lists:seq(Cols+1, NewCols)}, + S1 + end. + +handle_new_data_chunk2('$end_of_table', + S0 = #holder{parent=Parent, sort=Opt, + key=Key, + table=Old, temp=New}) -> + Table = merge(Old, New, Key), + N = length(Table), + Parent ! {no_rows, N}, + sort(Opt#opt.sort_key, S0#holder{n=N, pid=undefine, + sort=Opt#opt{sort_key = undefined}, + table=Table, temp=[]}); +handle_new_data_chunk2(Data, S0 = #holder{columns=Cols0, source=ets, temp=Tab0}) -> + {Tab, Cols} = parse_ets_data(Data, Cols0, Tab0), + S0#holder{columns=Cols, temp=Tab}; +handle_new_data_chunk2(Data, S0 = #holder{source=mnesia, temp=Tab}) -> + S0#holder{temp=(Data ++ Tab)}. + +parse_ets_data([[Rec]|Rs], C, Tab) -> + parse_ets_data(Rs, max(tuple_size(Rec), C), [Rec|Tab]); +parse_ets_data([Recs|Rs], C0, Tab0) -> + {Tab, Cols} = parse_ets_data(Recs, C0, Tab0), + parse_ets_data(Rs, Cols, Tab); +parse_ets_data([], Cols, Tab) -> + {Tab, Cols}. + +sort(Col, S=#holder{n=N, parent=Parent, sort=Opt0, table=Table0}) -> + {Opt, Table} = sort(Col, Opt0, Table0), + Parent ! {refresh, 0, N-1}, + S#holder{sort=Opt, table=Table}. + +sort(Col, Opt = #opt{sort_key=Col, sort_incr=Bool}, Table) -> + {Opt#opt{sort_incr=not Bool}, lists:reverse(Table)}; +sort(Col, S=#opt{sort_incr=true}, Table) -> + {S#opt{sort_key=Col}, keysort(Col, Table)}; +sort(Col, S=#opt{sort_incr=false}, Table) -> + {S#opt{sort_key=Col}, lists:reverse(keysort(Col, Table))}. + +keysort(Col, Table) -> + Sort = fun([A0|_], [B0|_]) -> + A = try element(Col, A0) catch _:_ -> [] end, + B = try element(Col, B0) catch _:_ -> [] end, + case A == B of + true -> A0 =< B0; + false -> A < B + end; + (A0, B0) when is_tuple(A0), is_tuple(B0) -> + A = try element(Col, A0) catch _:_ -> [] end, + B = try element(Col, B0) catch _:_ -> [] end, + case A == B of + true -> A0 =< B0; + false -> A < B + end + end, + lists:sort(Sort, Table). + +search([Str, Row, Dir0, CaseSens], + S=#holder{parent=Parent, table=Table}) -> + Opt = case CaseSens of + true -> []; + false -> [caseless] + end, + {ok, Re} = re:compile(Str, Opt), + Dir = case Dir0 of + true -> 1; + false -> -1 + end, + Res = search(Row, Dir, Re, Table), + Parent ! {self(), Res}, + S#holder{search=Res}. + +search(Row, Dir, Re, Table) -> + Res = try lists:nth(Row+1, Table) of + Term -> + Str = io_lib:format("~w", [Term]), + re:run(Str, Re) + catch _:_ -> no_more + end, + case Res of + nomatch -> search(Row+Dir, Dir, Re, Table); + no_more -> false; + {match,_} -> Row + end. + +get_row(From, Row, Col, Table) -> + case lists:nth(Row+1, Table) of + [Object|_] when Col =:= all -> + From ! {self(), io_lib:format("~w", [Object])}; + [Object|_] when tuple_size(Object) >= Col -> + From ! {self(), io_lib:format("~w", [element(Col, Object)])}; + _ -> + From ! {self(), ""} + end. + +get_attr(From, Row, #holder{attrs=Attrs, search=Row}) -> + What = Attrs#attrs.searched, + From ! {self(), What}; +get_attr(From, Row, #holder{table=Table, attrs=Attrs}) -> + What = case lists:nth(Row+1, Table) of + [_|deleted] -> Attrs#attrs.deleted; + [_|changed] -> Attrs#attrs.changed; + [_|new] -> Attrs#attrs.changed; + _ when (Row rem 2) > 0 -> + Attrs#attrs.odd; + _ -> + Attrs#attrs.even + end, + From ! {self(), What}. + +merge([], New, _Key) -> + [[N] || N <- New]; %% First time +merge(Old, New, Key) -> + merge2(keysort(Key, Old), keysort(Key, New), Key). + +merge2([[Obj|_]|Old], [Obj|New], Key) -> + [[Obj]|merge2(Old, New, Key)]; +merge2([[A|_]|Old], [B|New], Key) + when element(Key, A) == element(Key, B) -> + [[B|changed]|merge2(Old, New, Key)]; +merge2([[A|_]|Old], New = [B|_], Key) + when element(Key, A) < element(Key, B) -> + [[A|deleted]|merge2(Old, New, Key)]; +merge2(Old = [[A|_]|_], [B|New], Key) + when element(Key, A) > element(Key, B) -> + [[B|new]|merge2(Old, New, Key)]; +merge2([], New, _Key) -> + [[N|new] || N <- New]; +merge2(Old, [], _Key) -> + [[O|deleted] || [O|_] <- Old]. + + +delete_row(Row, S0 = #holder{parent=Parent}) -> + case delete(Row, S0) of + ok -> + self() ! refresh; + {error, Err} -> + Parent ! {error, "Could not delete object: " ++ Err} + end. + + +delete(Row, #holder{tabid=Id, table=Table, + source=Source, node=Node}) -> + [Object|_] = lists:nth(Row+1, Table), + try + case Source of + ets -> + true = rpc:call(Node, ets, delete_object, [Id, Object]); + mnesia -> + ok = rpc:call(Node, mnesia, dirty_delete_object, [Id, Object]) + end, + ok + catch _:_Error -> + {error, "node or table is not available"} + end. + +edit_row(Row, Term, S0 = #holder{parent=Parent}) -> + case delete(Row, S0) of + ok -> + case insert(Term, S0) of + ok -> self() ! refresh; + Err -> Parent ! {error, Err} + end; + {error, Err} -> + Parent ! {error, "Could not edit object: " ++ Err} + end. + +insert(Object, #holder{tabid=Id, source=Source, node=Node}) -> + try + case Source of + ets -> + true = rpc:call(Node, ets, insert, [Id, Object]); + mnesia -> + ok = rpc:call(Node, mnesia, dirty_write, [Id, Object]) + end, + ok + catch _:_Error -> + {error, "node or table is not available"} + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_table(Parent, Table, Module) -> + spawn(fun() -> + link(Parent), + get_table2(Parent, Table, Module) + end). + +get_table2(Parent, Table, Type) -> + Size = case Type of + ets -> ets:info(Table, size); + mnesia -> mnesia:table_info(Table, size) + end, + case Size > 0 of + false -> + Parent ! {self(), '$end_of_table'}, + normal; + true when Type =:= ets -> + Mem = ets:info(Table, memory), + Average = Mem div Size, + NoElements = max(10, 20000 div Average), + get_ets_loop(Parent, ets:match(Table, '$1', NoElements)); + true -> + Mem = mnesia:table_info(Table, memory), + Average = Mem div Size, + NoElements = max(10, 20000 div Average), + Ms = [{'$1', [], ['$1']}], + Get = fun() -> + get_mnesia_loop(Parent, mnesia:select(Table, Ms, NoElements, read)) + end, + %% Not a transaction, we don't want to grab locks when inspecting the table + mnesia:async_dirty(Get) + end. + +get_ets_loop(Parent, '$end_of_table') -> + Parent ! {self(), '$end_of_table'}; +get_ets_loop(Parent, {Match, Cont}) -> + Parent ! {self(), Match}, + get_ets_loop(Parent, ets:match(Cont)). + +get_mnesia_loop(Parent, '$end_of_table') -> + Parent ! {self(), '$end_of_table'}; +get_mnesia_loop(Parent, {Match, Cont}) -> + Parent ! {self(), Match}, + get_ets_loop(Parent, mnesia:select(Cont)). + +column_names(Node, Type, Table) -> + case Type of + ets -> [1, 2]; + mnesia -> + Attrs = rpc:call(Node, mnesia, table_info, [Table, attributes]), + is_list(Attrs) orelse throw(node_or_table_down), + ["Record Name"|Attrs] + end. + +table_id(#tab{id=ignore, name=Name}) -> Name; +table_id(#tab{id=Id}) -> Id. + +key_pos(_, mnesia, _) -> 2; +key_pos(Node, ets, TabId) -> + KeyPos = rpc:call(Node, ets, info, [TabId, keypos]), + is_integer(KeyPos) orelse throw(node_or_table_down), + KeyPos. diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl new file mode 100644 index 0000000000..ded03fadb1 --- /dev/null +++ b/lib/observer/src/observer_tv_wx.erl @@ -0,0 +1,475 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(observer_tv_wx). + +-export([start_link/2, display_table_info/4]). + +%% wx_object callbacks +-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, + handle_event/2, handle_sync_event/3, handle_cast/2]). + +-export([get_table_list/1]). %% RPC called move to runtime tools? + +-behaviour(wx_object). +-include_lib("wx/include/wx.hrl"). +-include("observer_defs.hrl"). +-include("observer_tv.hrl"). + +-define(GRID, 500). +-define(ID_REFRESH, 401). +-define(ID_REFRESH_INTERVAL, 402). +-define(ID_ETS, 403). +-define(ID_MNESIA, 404). +-define(ID_UNREADABLE, 405). +-define(ID_SYSTEM_TABLES, 406). +-define(ID_TABLE_INFO, 407). + +-record(opt, {type=ets, + sys_hidden=true, + unread_hidden=true, + sort_key=2, + sort_incr=true + }). + +-record(state, + { + parent, + grid, + node=node(), + opt=#opt{}, + selected, + tabs, + timer + }). + +start_link(Notebook, Parent) -> + wx_object:start_link(?MODULE, [Notebook, Parent], []). + +init([Notebook, Parent]) -> + Panel = wxPanel:new(Notebook), + Sizer = wxBoxSizer:new(?wxVERTICAL), + Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, + Grid = wxListCtrl:new(Panel, [{winid, ?GRID}, {style, Style}]), + wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL}, + {proportion, 1}, {border, 5}]), + wxWindow:setSizer(Panel, Sizer), + Li = wxListItem:new(), + AddListEntry = fun({Name, Align, DefSize}, Col) -> + wxListItem:setText(Li, Name), + wxListItem:setAlign(Li, Align), + wxListCtrl:insertColumn(Grid, Col, Li), + wxListCtrl:setColumnWidth(Grid, Col, DefSize), + Col + 1 + end, + ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, 200}, + {"Table Id", ?wxLIST_FORMAT_RIGHT, 100}, + {"Objects", ?wxLIST_FORMAT_RIGHT, 100}, + {"Size (kB)", ?wxLIST_FORMAT_RIGHT, 100}, + {"Owner Pid", ?wxLIST_FORMAT_CENTER, 150}, + {"Owner Name", ?wxLIST_FORMAT_LEFT, 200} + ], + lists:foldl(AddListEntry, 0, ListItems), + wxListItem:destroy(Li), + + wxListCtrl:connect(Grid, command_list_item_activated), + wxListCtrl:connect(Grid, command_list_item_selected), + wxListCtrl:connect(Grid, command_list_col_click), + wxListCtrl:connect(Grid, size, [{skip, true}]), + + wxWindow:setFocus(Grid), + Timer = observer_lib:start_timer(10), + {Panel, #state{grid=Grid, parent=Parent, timer=Timer}}. + +handle_event(#wx{id=?ID_REFRESH}, + State = #state{node=Node, grid=Grid, opt=Opt}) -> + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + {noreply, State#state{tabs=Tabs}}; + +handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}}, + State = #state{node=Node, grid=Grid, + opt=Opt0=#opt{sort_key=Key, sort_incr=Bool}}) -> + Opt = case Col+2 of + Key -> Opt0#opt{sort_incr=not Bool}; + NewKey -> Opt0#opt{sort_key=NewKey} + end, + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + wxWindow:setFocus(Grid), + {noreply, State#state{opt=Opt, tabs=Tabs}}; + +handle_event(#wx{id=Id}, State = #state{node=Node, grid=Grid, opt=Opt0}) + when Id >= ?ID_ETS, Id =< ?ID_SYSTEM_TABLES -> + Opt = case Id of + ?ID_ETS -> Opt0#opt{type=ets}; + ?ID_MNESIA -> Opt0#opt{type=mnesia}; + ?ID_UNREADABLE -> Opt0#opt{unread_hidden= not Opt0#opt.unread_hidden}; + ?ID_SYSTEM_TABLES -> Opt0#opt{sys_hidden= not Opt0#opt.sys_hidden} + end, + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + wxWindow:setFocus(Grid), + {noreply, State#state{opt=Opt, tabs=Tabs}}; + +handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) -> + wx:batch(fun() -> + Cols = wxListCtrl:getColumnCount(Grid), + Last = lists:foldl(fun(I, Last) -> + Last - wxListCtrl:getColumnWidth(Grid, I) + end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)), + Size = max(200, Last), + wxListCtrl:setColumnWidth(Grid, Cols-1, Size) + end), + {noreply, State}; + +handle_event(#wx{obj=Grid, event=#wxList{type=command_list_item_activated, + itemIndex=Index}}, + State=#state{grid=Grid, node=Node, opt=#opt{type=Type}, tabs=Tabs}) -> + Table = lists:nth(Index+1, Tabs), + case Table#tab.protection of + private -> + self() ! {error, "Table has 'private' protection and can not be read"}; + _ -> + observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]) + end, + {noreply, State}; + +handle_event(#wx{event=#wxList{type=command_list_item_selected, itemIndex=Index}}, + State) -> + {noreply, State#state{selected=Index}}; + +handle_event(#wx{id=?ID_TABLE_INFO}, + State = #state{grid=Grid, node=Node, opt=#opt{type=Type}, tabs=Tabs, selected=Sel}) -> + case Sel of + undefined -> + {noreply, State}; + R when is_integer(R) -> + Table = lists:nth(Sel+1, Tabs), + display_table_info(Grid, Node, Type, Table), + {noreply, State} + end; + +handle_event(#wx{id=?ID_REFRESH_INTERVAL}, + State = #state{grid=Grid, timer=Timer0}) -> + Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60), + {noreply, State#state{timer=Timer}}; + +handle_event(Event, State) -> + io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), + {noreply, State}. + +handle_sync_event(_Event, _Obj, _State) -> + ok. + +handle_call(_Event, _From, State) -> + {noreply, State}. + +handle_cast(_Event, State) -> + {noreply, State}. + +handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt}) -> + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + {noreply, State#state{tabs=Tabs}}; + +handle_info({active, Node}, State = #state{parent=Parent, grid=Grid, opt=Opt, + timer=Timer0}) -> + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + wxWindow:setFocus(Grid), + create_menus(Parent, Opt), + Timer = observer_lib:start_timer(Timer0), + {noreply, State#state{node=Node, tabs=Tabs, timer=Timer}}; + +handle_info(not_active, State = #state{timer = Timer0}) -> + Timer = observer_lib:stop_timer(Timer0), + {noreply, State#state{timer=Timer}}; + +handle_info({node, Node}, State = #state{grid=Grid, opt=Opt}) -> + Tables = get_tables(Node, Opt), + Tabs = update_grid(Grid, Opt, Tables), + wxWindow:setFocus(Grid), + {noreply, State#state{node=Node, tabs=Tabs}}; + +handle_info({error, Error}, State) -> + handle_error(Error), + {noreply, State}; + +handle_info(_Event, State) -> + {noreply, State}. + +terminate(_Event, _State) -> + ok. + +code_change(_, _, State) -> + State. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +create_menus(Parent, #opt{sys_hidden=Sys, unread_hidden=UnR, type=Type}) -> + MenuEntries = [{"View", + [#create_menu{id = ?ID_TABLE_INFO, text = "Table information\tCtrl-I"}, + separator, + #create_menu{id = ?ID_ETS, text = "&Ets Tables", + type=radio, check=Type==ets}, + #create_menu{id = ?ID_MNESIA, text = "&Mnesia Tables", + type=radio, check=Type==mnesia}, + separator, + #create_menu{id = ?ID_UNREADABLE, text = "View &Unreadable Tables", + type=check, check=not UnR}, + #create_menu{id = ?ID_SYSTEM_TABLES, text = "View &System Tables", + type=check, check=not Sys}, + separator, + #create_menu{id = ?ID_REFRESH, text = "Refresh\tCtrl-R"}, + #create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh Interval..."} + ]}], + observer_wx:create_menus(Parent, MenuEntries). + +get_tables(Node, Opt) -> + case rpc:call(Node, ?MODULE, get_table_list, [Opt]) of + {badrpc, Error} -> + self() ! {error, Error}, + []; + {error, Error} -> + self() ! {error, Error}, + []; + Result -> + Result + end. + +get_table_list(#opt{type=ets, unread_hidden=HideUnread, sys_hidden=HideSys}) -> + Info = fun(Id, Acc) -> + try + TabId = case ets:info(Id, named_table) of + true -> ignore; + false -> Id + end, + Name = ets:info(Id, name), + Protection = ets:info(Id, protection), + ignore(HideUnread andalso Protection == private, unreadable), + Owner = ets:info(Id, owner), + RegName = case catch process_info(Owner, registered_name) of + [] -> ignore; + {registered_name, ProcName} -> ProcName + end, + ignore(HideSys andalso ordsets:is_element(RegName, sys_processes()), system_tab), + ignore(HideSys andalso ordsets:is_element(Name, sys_tables()), system_tab), + ignore((RegName == mnesia_monitor) + andalso Name /= schema + andalso is_atom((catch mnesia:table_info(Name, where_to_read))), mnesia_tab), + Memory = ets:info(Id, memory) * erlang:system_info(wordsize), + Tab = #tab{name = Name, + id = TabId, + protection = Protection, + owner = Owner, + size = ets:info(Id, size), + reg_name = RegName, + type = ets:info(Id, type), + keypos = ets:info(Id, keypos), + heir = ets:info(Id, heir), + memory = Memory, + compressed = ets:info(Id, compressed), + fixed = ets:info(Id, fixed) + }, + [Tab|Acc] + catch _:_What -> + %% io:format("Skipped ~p: ~p ~n",[Id, _What]), + Acc + end + end, + lists:foldl(Info, [], ets:all()); +get_table_list(#opt{type=mnesia, sys_hidden=HideSys}) -> + Owner = ets:info(schema, owner), + Owner /= undefined orelse + throw({error, "Mnesia is not running on: " ++ atom_to_list(node())}), + {registered_name, RegName} = process_info(Owner, registered_name), + Info = fun(Id, Acc) -> + try + Name = Id, + ignore(HideSys andalso ordsets:is_element(Name, mnesia_tables()), system_tab), + ignore(Name =:= schema, mnesia_tab), + Storage = mnesia:table_info(Id, storage_type), + Tab0 = #tab{name = Name, + owner = Owner, + size = mnesia:table_info(Id, size), + reg_name = RegName, + type = mnesia:table_info(Id, type), + keypos = 2, + memory = mnesia:table_info(Id, memory) * erlang:system_info(wordsize), + storage = Storage, + index = mnesia:table_info(Id, index) + }, + Tab = if Storage == disc_only_copies -> + Tab0#tab{fixed = element(2, dets:info(Id, safe_fixed)) /= []}; + (Storage == ram_copies) orelse + (Storage == disc_copies) -> + Tab0#tab{fixed = ets:info(Id, fixed), + compressed = ets:info(Id, compressed)}; + true -> Tab0 + end, + [Tab|Acc] + catch _:_What -> + %% io:format("Skipped ~p: ~p ~n",[Id, _What]), + Acc + end + end, + lists:foldl(Info, [], mnesia:system_info(tables)). + +display_table_info(Parent0, Node, Source, Table) -> + Parent = observer_lib:get_wx_parent(Parent0), + Title = "Table Info: " ++ atom_to_list(Table#tab.name), + Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title, + [{style, ?wxSYSTEM_MENU bor ?wxCAPTION + bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}]), + + IdInfo = {"Identification and Owner", + [{"Name", Table#tab.name}, + {"Id", case Table#tab.id of + ignore -> Table#tab.name; + Id -> Id + end}, + {"Named table", Table#tab.id == ignore}, + {"Owner", Table#tab.owner}, + {"Owner Name", case Table#tab.reg_name of + ignore -> "-"; + Id -> Id + end}, + {"Heir", Table#tab.heir}, + {"Node", Node}]}, + MnesiaSettings = case Source of + ets -> []; + mnesia -> + [{"Local storage type", case Table#tab.storage of + unknown -> "Not available"; + ST -> ST + end}, + {"Index positions", list_to_strings(Table#tab.index)}] + end, + Settings = {"Settings", + [{"Source", Source}, + {"Key Position", Table#tab.keypos}, + {"Table Type", Table#tab.type}, + {"Protection Mode", Table#tab.protection}, + {"Fixed", Table#tab.fixed} + | MnesiaSettings ]}, + Memory = {"Memory Usage", + [{"Number of objects", Table#tab.size}, + {"Memory allocated", {bytes, Table#tab.memory}}, + {"Compressed", Table#tab.compressed}]}, + + {_, Sizer, _} = observer_lib:display_info(Frame, [IdInfo,Settings,Memory]), + wxSizer:setSizeHints(Sizer, Frame), + wxFrame:center(Frame), + wxFrame:show(Frame). + +list_to_strings([]) -> "None"; +list_to_strings([A]) -> integer_to_list(A); +list_to_strings([A,B]) -> + integer_to_list(A) ++ " ," ++ list_to_strings(B). + +sys_tables() -> + [ac_tab, asn1, + cdv_dump_index_table, cdv_menu_table, cdv_decode_heap_table, + cell_id, cell_pos, clist, + cover_internal_data_table, cover_collected_remote_data_table, cover_binary_code_table, + code, code_names, cookies, + corba_policy, corba_policy_associations, + dets, dets_owners, dets_registry, + disk_log_names, disk_log_pids, + eprof, erl_atom_cache, erl_epmd_nodes, + etop_accum_tab, etop_tr, + ets_coverage_data, + file_io_servers, + gs_mapping, gs_names, gstk_db, + gstk_grid_cellid, gstk_grid_cellpos, gstk_grid_id, + httpd, + id, + ign_req_index, ign_requests, + index, + inet_cache, inet_db, inet_hosts, + 'InitialReferences', + int_db, + interpreter_includedirs_macros, + ir_WstringDef, + lmcounter, locks, +% mnesia_decision, + mnesia_gvar, mnesia_stats, +% mnesia_transient_decision, + pg2_table, + queue, + schema, + shell_records, + snmp_agent_table, snmp_local_db2, snmp_mib_data, snmp_note_store, snmp_symbolic_ets, + tkFun, tkLink, tkPriv, + ttb, ttb_history_table, + udp_fds, udp_pids + ]. + +sys_processes() -> + [auth, code_server, global_name_server, inet_db, + mnesia_recover, net_kernel, timer_server, wxe_master]. + +mnesia_tables() -> + [ir_AliasDef, ir_ArrayDef, ir_AttributeDef, ir_ConstantDef, + ir_Contained, ir_Container, ir_EnumDef, ir_ExceptionDef, + ir_IDLType, ir_IRObject, ir_InterfaceDef, ir_ModuleDef, + ir_ORB, ir_OperationDef, ir_PrimitiveDef, ir_Repository, + ir_SequenceDef, ir_StringDef, ir_StructDef, ir_TypedefDef, + ir_UnionDef, logTable, logTransferTable, mesh_meas, + mesh_type, mnesia_clist, orber_CosNaming, + orber_objkeys, user + ]. + +handle_error(Foo) -> + Str = io_lib:format("ERROR: ~s~n",[Foo]), + observer_lib:display_info_dialog(Str). + +update_grid(Grid, Opt, Tables) -> + wx:batch(fun() -> update_grid2(Grid, Opt, Tables) end). +update_grid2(Grid, #opt{sort_key=Sort,sort_incr=Dir}, Tables) -> + wxListCtrl:deleteAllItems(Grid), + Update = + fun(#tab{name = Name, id = Id, owner = Owner, size = Size, memory = Memory, + protection = Protection, reg_name = RegName}, Row) -> + _Item = wxListCtrl:insertItem(Grid, Row, ""), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(Grid, Row, ?BG_EVEN); + true -> ignore + end, + if Protection == private -> + wxListCtrl:setItemTextColour(Grid, Row, {200,130,50}); + true -> ignore + end, + + lists:foreach(fun({_, ignore}) -> ignore; + ({Col, Val}) -> + wxListCtrl:setItem(Grid, Row, Col, observer_lib:to_str(Val)) + end, + [{0,Name}, {1,Id}, {2,Size}, {3, Memory div 1024}, + {4,Owner}, {5,RegName}]), + Row + 1 + end, + ProcInfo = case Dir of + false -> lists:reverse(lists:keysort(Sort, Tables)); + true -> lists:keysort(Sort, Tables) + end, + lists:foldl(Update, 0, ProcInfo), + ProcInfo. + +ignore(true, Reason) -> throw(Reason); +ignore(_,_ ) -> ok. diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl new file mode 100644 index 0000000000..f9dec1ab1b --- /dev/null +++ b/lib/observer/src/observer_wx.erl @@ -0,0 +1,537 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(observer_wx). + +-behaviour(wx_object). + +-export([start/0]). +-export([create_menus/2, get_attrib/1, get_tracer/0, + create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). + +-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, + handle_call/3, handle_info/2, check_page_title/1]). + +%% Includes +-include_lib("wx/include/wx.hrl"). + +-include("observer_defs.hrl"). + +%% Defines + +-define(ID_PING, 1). +-define(ID_CONNECT, 2). +-define(ID_NOTEBOOK, 3). + +-define(FIRST_NODES_MENU_ID, 1000). +-define(LAST_NODES_MENU_ID, 2000). + +-define(TRACE_STR, "Trace Overview"). + +%% Records +-record(state, + {frame, + menubar, + menus = [], + status_bar, + notebook, + main_panel, + pro_panel, + tv_panel, + sys_panel, + trace_panel, + active_tab, + node, + nodes + }). + +start() -> + wx_object:start(?MODULE, [], []). + +create_menus(Object, Menus) when is_list(Menus) -> + wx_object:call(Object, {create_menus, Menus}). + +get_attrib(What) -> + wx_object:call(observer, {get_attrib, What}). + +get_tracer() -> + wx_object:call(observer, get_tracer). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init(_Args) -> + register(observer, self()), + wx:new(), + catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1), + Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Observer", + [{size, {1000, 500}}, {style, ?wxDEFAULT_FRAME_STYLE}]), + IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), + Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), + wxFrame:setIcon(Frame, Icon), + wxIcon:destroy(Icon), + + State = #state{frame = Frame}, + UpdState = setup(State), + net_kernel:monitor_nodes(true), + process_flag(trap_exit, true), + {Frame, UpdState}. + +setup(#state{frame = Frame} = State) -> + %% Setup Menubar & Menus + MenuBar = wxMenuBar:new(), + + {Nodes, NodeMenus} = get_nodes(), + DefMenus = default_menus(NodeMenus), + observer_lib:create_menus(DefMenus, MenuBar, default), + + wxFrame:setMenuBar(Frame, MenuBar), + StatusBar = wxFrame:createStatusBar(Frame, []), + wxFrame:setTitle(Frame, atom_to_list(node())), + wxStatusBar:setStatusText(StatusBar, atom_to_list(node())), + + %% Setup panels + Panel = wxPanel:new(Frame, []), + Notebook = wxNotebook:new(Panel, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]), + + %% System Panel + SysPanel = observer_sys_wx:start_link(Notebook, self()), + wxNotebook:addPage(Notebook, SysPanel, "System", []), + + %% Setup sizer create early to get it when window shows + MainSizer = wxBoxSizer:new(?wxVERTICAL), + + wxSizer:add(MainSizer, Notebook, [{proportion, 1}, {flag, ?wxEXPAND}]), + wxPanel:setSizer(Panel, MainSizer), + + wxNotebook:connect(Notebook, command_notebook_page_changing), + wxFrame:connect(Frame, close_window, [{skip, true}]), + wxMenu:connect(Frame, command_menu_selected), + wxFrame:show(Frame), + + %% I postpone the creation of the other tabs so they can query/use + %% the window size + + %% Process Panel + ProPanel = observer_pro_wx:start_link(Notebook, self()), + wxNotebook:addPage(Notebook, ProPanel, "Processes", []), + + %% Table Viewer Panel + TVPanel = observer_tv_wx:start_link(Notebook, self()), + wxNotebook:addPage(Notebook, TVPanel, "Table Viewer", []), + + %% Trace Viewer Panel + TracePanel = observer_trace_wx:start_link(Notebook, self()), + wxNotebook:addPage(Notebook, TracePanel, ?TRACE_STR, []), + + %% Force redraw (window needs it) + wxWindow:refresh(Panel), + + SysPid = wx_object:get_pid(SysPanel), + SysPid ! {active, node()}, + UpdState = State#state{main_panel = Panel, + notebook = Notebook, + menubar = MenuBar, + status_bar = StatusBar, + sys_panel = SysPanel, + pro_panel = ProPanel, + tv_panel = TVPanel, + trace_panel = TracePanel, + active_tab = SysPid, + node = node(), + nodes = Nodes + }, + %% Create resources which we don't want to duplicate + SysFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + SysFontSize = wxFont:getPointSize(SysFont), + Modern = wxFont:new(SysFontSize, ?wxFONTFAMILY_MODERN, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), + put({font, modern}, Modern), + put({font, fixed}, Modern), + UpdState. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%Callbacks +handle_event(#wx{event=#wxNotebook{type=command_notebook_page_changing}}, + #state{active_tab=Previous, node=Node} = State) -> + Pid = get_active_pid(State), + Previous ! not_active, + Pid ! {active, Node}, + {noreply, State#state{active_tab=Pid}}; + +handle_event(#wx{event = #wxClose{}}, State) -> + {stop, normal, State}; + +handle_event(#wx{id = ?wxID_EXIT, event = #wxCommand{type = command_menu_selected}}, State) -> + {stop, normal, State}; + +handle_event(#wx{id = ?wxID_HELP, event = #wxCommand{type = command_menu_selected}}, State) -> + External = "http://www.erlang.org/doc/apps/observer/index.html", + Internal = filename:join([code:lib_dir(observer),"doc", "html", "index.html"]), + Help = case filelib:is_file(Internal) of + true -> Internal; + false -> External + end, + wx_misc:launchDefaultBrowser(Help) orelse + create_txt_dialog(State#state.frame, "Could not launch browser: ~n " ++ Help, + "Error", ?wxICON_ERROR), + {noreply, State}; + +handle_event(#wx{id = ?wxID_ABOUT, event = #wxCommand{type = command_menu_selected}}, + State = #state{frame=Frame}) -> + AboutString = "Observe an erlang system\n" + "Authors: Olle Mattson & Magnus Eriksson & Dan Gudmundsson", + Style = [{style, ?wxOK bor ?wxSTAY_ON_TOP}, + {caption, "About"}], + wxMessageDialog:showModal(wxMessageDialog:new(Frame, AboutString, Style)), + {noreply, State}; + + +handle_event(#wx{id = ?ID_CONNECT, event = #wxCommand{type = command_menu_selected}}, + #state{frame = Frame} = State) -> + UpdState = case create_connect_dialog(connect, State) of + cancel -> + State; + {value, [], _, _} -> + create_txt_dialog(Frame, "Node must have a name", + "Error", ?wxICON_ERROR), + State; + {value, NodeName, LongOrShort, Cookie} -> %Shortname, + try + case connect(list_to_atom(NodeName), LongOrShort, list_to_atom(Cookie)) of + {ok, set_cookie} -> + change_node_view(node(), State); + {error, set_cookie} -> + create_txt_dialog(Frame, "Could not set cookie", + "Error", ?wxICON_ERROR), + State; + {error, net_kernel, _Reason} -> + create_txt_dialog(Frame, "Could not enable node", + "Error", ?wxICON_ERROR), + State + end + catch _:_ -> + create_txt_dialog(Frame, "Could not enable node", + "Error", ?wxICON_ERROR), + State + end + end, + {noreply, UpdState}; + +handle_event(#wx{id = ?ID_PING, event = #wxCommand{type = command_menu_selected}}, + #state{frame = Frame} = State) -> + UpdState = case create_connect_dialog(ping, State) of + cancel -> State; + {value, Value} when is_list(Value) -> + try + Node = list_to_atom(Value), + case net_adm:ping(Node) of + pang -> + create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION), + State; + pong -> + change_node_view(Node, State) + end + catch _:_ -> + create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION), + State + end + end, + {noreply, UpdState}; + +handle_event(#wx{id = Id, event = #wxCommand{type = command_menu_selected}}, State) + when Id > ?FIRST_NODES_MENU_ID, Id < ?LAST_NODES_MENU_ID -> + + Node = lists:nth(Id - ?FIRST_NODES_MENU_ID, State#state.nodes), + UpdState = change_node_view(Node, State), + {noreply, UpdState}; + +handle_event(Event, State) -> + Pid = get_active_pid(State), + Pid ! Event, + {noreply, State}. + +handle_cast(_Cast, State) -> + {noreply, State}. + +handle_call({create_menus, TabMenus}, _From, + State = #state{menubar=MenuBar, menus=PrevTabMenus}) -> + wx:batch(fun() -> + clean_menus(PrevTabMenus, MenuBar), + observer_lib:create_menus(TabMenus, MenuBar, plugin) + end), + {reply, ok, State#state{menus=TabMenus}}; + +handle_call({get_attrib, Attrib}, _From, State) -> + {reply, get(Attrib), State}; + +handle_call(get_tracer, _From, State=#state{trace_panel=TraceP}) -> + {reply, TraceP, State}; + +handle_call(_Msg, _From, State) -> + {reply, ok, State}. + +handle_info({nodeup, _Node}, State) -> + State2 = update_node_list(State), + {noreply, State2}; + +handle_info({nodedown, Node}, + #state{frame = Frame} = State) -> + State2 = case Node =:= State#state.node of + true -> + change_node_view(node(), State); + false -> + State + end, + State3 = update_node_list(State2), + Msg = ["Node down: " | atom_to_list(Node)], + create_txt_dialog(Frame, Msg, "Node down", ?wxICON_EXCLAMATION), + {noreply, State3}; + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, #state{frame = Frame}) -> + wxFrame:destroy(Frame), + ok. + +code_change(_, _, State) -> + {stop, not_yet_implemented, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +try_rpc(Node, Mod, Func, Args) -> + case + rpc:call(Node, Mod, Func, Args) of + {badrpc, Reason} -> + error_logger:error_report([{node, Node}, + {call, {Mod, Func, Args}}, + {reason, {badrpc, Reason}}]), + error({badrpc, Reason}); + Res -> + Res + end. + +return_to_localnode(Frame, Node) -> + case node() =/= Node of + true -> + create_txt_dialog(Frame, "Error occured on remote node", + "Error", ?wxICON_ERROR), + disconnect_node(Node); + false -> + ok + end. + +create_txt_dialog(Frame, Msg, Title, Style) -> + MD = wxMessageDialog:new(Frame, Msg, [{style, Style}]), + wxMessageDialog:setTitle(MD, Title), + wxDialog:showModal(MD), + wxDialog:destroy(MD). + +connect(NodeName, 0, Cookie) -> + connect2(NodeName, shortnames, Cookie); +connect(NodeName, 1, Cookie) -> + connect2(NodeName, longnames, Cookie). + +connect2(NodeName, Opts, Cookie) -> + case net_adm:names() of + {ok, _} -> %% Epmd is running + ok; + {error, address} -> + Epmd = os:find_executable("epmd"), + os:cmd(Epmd) + end, + case net_kernel:start([NodeName, Opts]) of + {ok, _} -> + case is_alive() of + true -> + erlang:set_cookie(node(), Cookie), + {ok, set_cookie}; + false -> + {error, set_cookie} + end; + {error, Reason} -> + {error, net_kernel, Reason} + end. + +change_node_view(Node, State = #state{pro_panel=Pro, sys_panel=Sys, tv_panel=Tv}) -> + lists:foreach(fun(Pid) -> wx_object:get_pid(Pid) ! {node, Node} end, + [Pro, Sys, Tv]), + StatusText = ["Observer - " | atom_to_list(Node)], + wxFrame:setTitle(State#state.frame, StatusText), + wxStatusBar:setStatusText(State#state.status_bar, StatusText), + State#state{node = Node}. + +check_page_title(Notebook) -> + Selection = wxNotebook:getSelection(Notebook), + wxNotebook:getPageText(Notebook, Selection). + +get_active_pid(#state{notebook=Notebook, pro_panel=Pro, sys_panel=Sys, tv_panel=Tv, trace_panel=Trace}) -> + Panel = case check_page_title(Notebook) of + "Processes" -> Pro; + "System" -> Sys; + "Table Viewer" -> Tv; + ?TRACE_STR -> Trace + end, + wx_object:get_pid(Panel). + +create_connect_dialog(ping, #state{frame = Frame}) -> + Dialog = wxTextEntryDialog:new(Frame, "Connect to node"), + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + Value = wxTextEntryDialog:getValue(Dialog), + wxDialog:destroy(Dialog), + {value, Value}; + ?wxID_CANCEL -> + wxDialog:destroy(Dialog), + cancel + end; +create_connect_dialog(connect, #state{frame = Frame}) -> + Dialog = wxDialog:new(Frame, ?wxID_ANY, "Distribute node "), + + VSizer = wxBoxSizer:new(?wxVERTICAL), + RadioBoxSizer = wxBoxSizer:new(?wxHORIZONTAL), + + Choices = ["Short name", "Long name"], + RadioBox = wxRadioBox:new(Dialog, 1, "", + ?wxDefaultPosition, + ?wxDefaultSize, + Choices, + [{majorDim, 2}, + {style, ?wxHORIZONTAL}]), + + NameText = wxStaticText:new(Dialog, ?wxID_ANY, "Node name: "), + NameCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {200, 25}}]), + wxTextCtrl:setValue(NameCtrl, "observer"), + CookieText = wxStaticText:new(Dialog, ?wxID_ANY, "Secret cookie: "), + CookieCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY, + [{size, {200, 25}}, {style, ?wxTE_PASSWORD}]), + + BtnSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxID_DEFAULT), + Flags = [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}], + wxSizer:add(RadioBoxSizer, RadioBox, Flags), + + wxSizer:add(VSizer, RadioBoxSizer, Flags), + wxSizer:addSpacer(VSizer, 10), + wxSizer:add(VSizer, NameText), + wxSizer:add(VSizer, NameCtrl, Flags), + wxSizer:addSpacer(VSizer, 10), + wxSizer:add(VSizer, CookieText), + wxSizer:add(VSizer, CookieCtrl, Flags), + wxSizer:addSpacer(VSizer, 10), + wxSizer:add(VSizer, BtnSizer, [{flag, ?wxALIGN_LEFT}]), + + wxWindow:setSizer(Dialog, VSizer), + CookiePath = filename:join(os:getenv("HOME"), ".erlang.cookie"), + DefaultCookie = case filelib:is_file(CookiePath) of + true -> + {ok, Bin} = file:read_file(CookiePath), + binary_to_list(Bin); + false -> + "" + end, + wxTextCtrl:setValue(CookieCtrl, DefaultCookie), + case wxDialog:showModal(Dialog) of + ?wxID_OK -> + NameValue = wxTextCtrl:getValue(NameCtrl), + NameLngthValue = wxRadioBox:getSelection(RadioBox), + CookieValue = wxTextCtrl:getValue(CookieCtrl), + wxDialog:destroy(Dialog), + {value, NameValue, NameLngthValue, CookieValue}; + ?wxID_CANCEL -> + wxDialog:destroy(Dialog), + cancel + end. + +default_menus(NodesMenuItems) -> + Quit = #create_menu{id = ?wxID_EXIT, text = "Quit"}, + About = #create_menu{id = ?wxID_ABOUT, text = "About"}, + Help = #create_menu{id = ?wxID_HELP}, + NodeMenu = case erlang:is_alive() of + true -> {"Nodes", NodesMenuItems ++ + [#create_menu{id = ?ID_PING, text = "Connect Node"}]}; + false -> {"Nodes", NodesMenuItems ++ + [#create_menu{id = ?ID_CONNECT, text = "Enable distribution"}]} + end, + case os:type() =:= {unix, darwin} of + false -> + FileMenu = {"File", [Quit]}, + HelpMenu = {"Help", [About,Help]}, + [FileMenu, NodeMenu, HelpMenu]; + true -> + %% On Mac quit and about will be moved to the "default' place + %% automagicly, so just add them to a menu that always exist. + %% But not to the help menu for some reason + {Tag, Menus} = NodeMenu, + [{Tag, Menus ++ [Quit,About]}, {"&Help", [Help]}] + end. + +clean_menus(Menus, MenuBar) -> + remove_menu_items(Menus, MenuBar). + +remove_menu_items([{MenuStr = "File", Menus}|Rest], MenuBar) -> + MenuId = wxMenuBar:findMenu(MenuBar, MenuStr), + Menu = wxMenuBar:getMenu(MenuBar, MenuId), + Items = [wxMenu:findItem(Menu, Tag) || #create_menu{text=Tag} <- Menus], + [wxMenu:delete(Menu, MItem) || MItem <- Items], + case os:type() =:= {unix, darwin} of + true -> + wxMenuBar:remove(MenuBar, MenuId), + wxMenu:destroy(Menu); + false -> + ignore + end, + remove_menu_items(Rest, MenuBar); +remove_menu_items([{"Nodes", _}|_], _MB) -> + ok; +remove_menu_items([{Tag, _Menus}|Rest], MenuBar) -> + MenuId = wxMenuBar:findMenu(MenuBar, Tag), + Menu = wxMenuBar:getMenu(MenuBar, MenuId), + wxMenuBar:remove(MenuBar, MenuId), + Items = wxMenu:getMenuItems(Menu), + [wxMenu:'Destroy'(Menu, Item) || Item <- Items], + wxMenu:destroy(Menu), + remove_menu_items(Rest, MenuBar); +remove_menu_items([], _MB) -> + ok. + +get_nodes() -> + Nodes = [node()| nodes()], + {_, Menues} = + lists:foldl(fun(Node, {Id, Acc}) when Id < ?LAST_NODES_MENU_ID -> + {Id + 1, [#create_menu{id=Id + ?FIRST_NODES_MENU_ID, + text=atom_to_list(Node)} | Acc]} + end, {1, []}, Nodes), + {Nodes, lists:reverse(Menues)}. + +update_node_list(State = #state{menubar=MenuBar}) -> + {Nodes, NodesMenuItems} = get_nodes(), + NodeMenuId = wxMenuBar:findMenu(MenuBar, "Nodes"), + NodeMenu = wxMenuBar:getMenu(MenuBar, NodeMenuId), + wx:foreach(fun(Item) -> wxMenu:'Destroy'(NodeMenu, Item) end, + wxMenu:getMenuItems(NodeMenu)), + + Index = wx:foldl(fun(Record, Index) -> + observer_lib:create_menu_item(Record, NodeMenu, Index) + end, 0, NodesMenuItems), + + Dist = case erlang:is_alive() of + true -> #create_menu{id = ?ID_PING, text = "Connect node"}; + false -> #create_menu{id = ?ID_CONNECT, text = "Enable distribution"} + end, + observer_lib:create_menu_item(Dist, NodeMenu, Index), + State#state{nodes = Nodes}. diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl index 072aa165e7..61fd6d1787 100644 --- a/lib/observer/src/ttb.erl +++ b/lib/observer/src/ttb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -75,29 +75,41 @@ do_tracer(Nodes0,PI,Client,Traci) -> do_tracer(Clients,PI,Traci). do_tracer(Clients,PI,Traci) -> - ShellOutput = proplists:get_value(shell, Traci, false), - {ClientSucc,Succ} = + Shell = proplists:get_value(shell, Traci, false), + DefShell = fun(Trace) -> dbg:dhandler(Trace, standard_io) end, + {ClientSucc,Succ} = lists:foldl( - fun({N,{local,File},TF},{CS,S}) -> - TF2 = case ShellOutput of - only -> none; - _ -> TF - end, - [_Sname,Host] = string:tokens(atom_to_list(N),"@"), + fun({N,{local,File},TF},{CS,S}) -> + {TF2, FileInfo, ShellOutput} = + case Shell of + only -> {none, shell_only, DefShell}; + true -> {TF, {file,File}, DefShell}; + {only,Fun} -> {none, shell_only, Fun}; + Fun when is_function(Fun) -> {TF, {file,File}, Fun}; + _ -> {TF, {file,File}, false} + end, + Host = case N of + nonode@nohost -> + {ok, H} = inet:gethostname(), + H; + _ -> + [_,H] = string:tokens(atom_to_list(N),"@"), + H + end, case catch dbg:tracer(N,port,dbg:trace_port(ip,0)) of {ok,N} -> {ok,Port} = dbg:trace_port_control(N,get_listen_port), {ok,T} = dbg:get_tracer(N), rpc:call(N,seq_trace,set_system_tracer,[T]), dbg:trace_client(ip,{Host,Port}, - {fun ip_to_file/2,{{file,File}, ShellOutput}}), + {fun ip_to_file/2,{FileInfo, ShellOutput}}), {[{N,{local,File,Port},TF2}|CS], [N|S]}; Other -> display_warning(N,{cannot_open_ip_trace_port, Host, Other}), {CS, S} - end; + end; ({N,C,_}=Client,{CS,S}) -> case catch dbg:tracer(N,port,dbg:trace_port(file,C)) of {ok,N} -> @@ -519,7 +531,7 @@ ensure_no_overloaded_nodes() -> []; _ -> ?MODULE ! {get_overloaded, self()}, - receive O -> O end + receive {overloaded,O} -> O end end, case Overloaded of [] -> ok; @@ -620,7 +632,7 @@ stop_opts(Opts) -> case {FormatData, lists:member(return_fetch_dir, Opts)} of {false, true} -> {fetch, FetchDir}; % if we specify return_fetch_dir, the data should be fetched - {false, false} -> + {false, false} -> case lists:member(nofetch,Opts) of false -> {fetch, FetchDir}; true -> nofetch @@ -687,6 +699,11 @@ loop(NodeInfo, SessionInfo) -> {MetaFile,undefined} end, loop(dict:store(Node,{AbsoluteMetaFile,MetaPid},NodeInfo), SessionInfo); + {ip_to_file_trace_port,Port,Sender} -> + Ports = proplists:get_value(ip_to_file_trace_ports, SessionInfo, []), + NewSessionInfo = [{ip_to_file_trace_ports,[Port|Ports]}|SessionInfo], + Sender ! {?MODULE,ok}, + loop(NodeInfo, NewSessionInfo); {get_nodes,Sender} -> Sender ! {?MODULE,dict:fetch_keys(NodeInfo)}, loop(NodeInfo, SessionInfo); @@ -715,7 +732,7 @@ loop(NodeInfo, SessionInfo) -> lists:keydelete(overloaded, 1, SessionInfo)}, loop(NodeInfo, [{overloaded, [Node|Overloaded]} | SI]); {get_overloaded, Pid} -> - Pid ! proplists:get_value(overloaded, SessionInfo, []), + Pid ! {overloaded,proplists:get_value(overloaded, SessionInfo, [])}, loop(NodeInfo, SessionInfo); trace_started -> case proplists:get_value(timer, SessionInfo) of @@ -736,7 +753,7 @@ loop(NodeInfo, SessionInfo) -> end end. -do_stop(nofetch, Sender, NodeInfo, _) -> +do_stop(nofetch, Sender, NodeInfo, SessionInfo) -> write_config(?last_config, all), dict:fold( fun(Node,{_,MetaPid},_) -> @@ -744,6 +761,7 @@ do_stop(nofetch, Sender, NodeInfo, _) -> end, ok, NodeInfo), + stop_ip_to_file_trace_ports(SessionInfo), dbg:stop_clear(), ets:delete(?history_table), Sender ! {?MODULE, stopped}; @@ -766,6 +784,7 @@ do_stop({FetchOrFormat, UserDir}, Sender, NodeInfo, SessionInfo) -> end, [], NodeInfo), + stop_ip_to_file_trace_ports(SessionInfo), dbg:stop_clear(), AllNodes = lists:map( @@ -784,6 +803,19 @@ do_stop({FetchOrFormat, UserDir}, Sender, NodeInfo, SessionInfo) -> end, Sender ! {?MODULE,{stopped,Absname}}. +stop_ip_to_file_trace_ports(SessionInfo) -> + lists:foreach(fun(Port) -> + case lists:member(Port,erlang:ports()) of + true -> + dbg:deliver_and_flush(Port), + erlang:port_close(Port); + false -> + ok + end + end, + proplists:get_value(ip_to_file_trace_ports,SessionInfo,[])). + + make_node_dead(Node, NodeInfo, SessionInfo) -> {MetaFile,_} = dict:fetch(Node, NodeInfo), NewDeadNodes = [{Node, MetaFile} | proplists:get_value(dead_nodes, SessionInfo)], @@ -1255,14 +1287,17 @@ display_warning(Item,Warning) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Trace client which reads an IP port and puts data directly to a file. %%% This is used when tracing remote nodes with no file system. -ip_to_file({metadata,_,_},{_, only} = State) -> +ip_to_file({metadata,_,_},{shell_only, _} = State) -> State; -ip_to_file(Trace, {_, only} = State) -> - dbg:dhandler(Trace, standard_io), +ip_to_file(Trace, {shell_only, Fun} = State) -> + Fun(Trace), State; ip_to_file(Trace,{{file,File}, ShellOutput}) -> Fun = dbg:trace_port(file,File), %File can be a filename or a wrap spec Port = Fun(), + %% Store the port so it can be properly closed + ?MODULE ! {ip_to_file_trace_port, Port, self()}, + receive {?MODULE,ok} -> ok end, case Trace of {metadata, _, _} -> ok; Trace -> show_trace(Trace, ShellOutput) @@ -1279,8 +1314,8 @@ ip_to_file(Trace,{Port, ShellOutput}) -> erlang:port_command(Port,B), {Port, ShellOutput}. -show_trace(Trace, true) -> - dbg:dhandler(Trace, standard_io); +show_trace(Trace, Fun) when is_function(Fun) -> + Fun(Trace); show_trace(_, _) -> ok. diff --git a/lib/observer/test/client.erl b/lib/observer/test/client.erl index e756f9d6e8..90b72d3f8f 100644 --- a/lib/observer/test/client.erl +++ b/lib/observer/test/client.erl @@ -23,6 +23,6 @@ get() -> put(Thing) -> erlang:send({server,server_node()}, {put,self(),Thing}), - receive ok -> ok + receive ok -> timer:sleep(2), ok after 1000 -> no_reply end. diff --git a/lib/observer/test/server.erl b/lib/observer/test/server.erl index c1b1fea562..f6d3542c96 100644 --- a/lib/observer/test/server.erl +++ b/lib/observer/test/server.erl @@ -16,8 +16,9 @@ stop() -> loop(Data, Num) -> receive - {put,From,Ting} -> From ! ok, + {put,From,Ting} -> timer:sleep(2), received(From,Ting), + From ! ok, loop([Ting|Data], Num+1); {get,From} -> From ! Data, loop(Data, Num+1); diff --git a/lib/observer/test/ttb_SUITE.erl b/lib/observer/test/ttb_SUITE.erl index 1fd8b4c892..695d41b48a 100644 --- a/lib/observer/test/ttb_SUITE.erl +++ b/lib/observer/test/ttb_SUITE.erl @@ -37,16 +37,30 @@ -define(FNAME, "temptest"). -define(DIRNAME, "ddtemp"). -init_per_testcase(_Case, Config) -> - ttb:stop(), - os:cmd("rm -rf " ++ ?OUTPUT), - os:cmd("rm -rf ttb_upload*"), - os:cmd("rm -rf " ++ ?DIRNAME), - os:cmd("rm -rf *@*"), - os:cmd("rm -rf ttb_last_config"), +init_per_testcase(Case, Config) -> ?line Dog=test_server:timetrap(?default_timeout), + ttb:stop(), + rm(?OUTPUT), + [rm(Upload) || Upload<-filelib:wildcard("ttb_upload*")], + rm(?DIRNAME), + [rm(At) || At <- filelib:wildcard("*@*")], + rm("ttb_last_config"), + %% Workaround for bug(?) in test_server - if the test case fails + %% with a timetrap timeout, then end_per_testcase will run with + %% faulty group_leader - which in turn makes test_server:stop_node + %% hang (stop_node is called by most of the cleanup functions). + %% Therefore we do the cleanup before each testcase instead - this + %% is obviously not 100% correct, but it will at least make sure + %% that the nodes which are to be started in a test case at are + %% terminated. + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> +end_per_testcase(Case, Config) -> + %% try apply(?MODULE,Case,[cleanup,Config]) + %% catch error:undef -> ok + %% end, Dog=?config(watchdog, Config), ?t:timetrap_cancel(Dog), ok. @@ -81,6 +95,7 @@ groups() -> []. init_per_suite(Config) -> + clean_priv_dir(Config), Config. end_per_suite(_Config) -> @@ -102,7 +117,7 @@ file(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"file"), ?line {ok,[Node]} = ttb:tracer(Node,[{file, File}, @@ -119,7 +134,6 @@ file(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), ?line ok = ttb:format(filename:join(Privdir, atom_to_list(OtherNode)++"-file")), @@ -130,6 +144,9 @@ file(Config) when is_list(Config) -> end_of_trace] = flush(), ok. +file(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + file_no_pi(suite) -> []; file_no_pi(doc) -> @@ -139,7 +156,7 @@ file_no_pi(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"file"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, @@ -150,7 +167,6 @@ file_no_pi(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), ?line ok = ttb:format(filename:join(Privdir, atom_to_list(OtherNode)++"-file")), @@ -163,6 +179,10 @@ file_no_pi(Config) when is_list(Config) -> ?line true = is_pid(RemoteProc), ok. +file_no_pi(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + + file_fetch(suite) -> []; file_fetch(doc) -> @@ -172,7 +192,7 @@ file_fetch(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line ThisDir = filename:join(Privdir,this), ?line ok = file:make_dir(ThisDir), ?line OtherDir = filename:join(Privdir,other), @@ -201,7 +221,6 @@ file_fetch(Config) when is_list(Config) -> ?line [StoreString] = ?t:capture_get(), ?line UploadDir = lists:last(string:tokens(lists:flatten(StoreString),"$ \n")), - ?line ?t:stop_node(OtherNode), %% check that files are no longer in original directories... ?line ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch"), @@ -228,6 +247,10 @@ file_fetch(Config) when is_list(Config) -> ?line ok = file:set_cwd(Cwd), ok. +file_fetch(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + + wrap(suite) -> []; wrap(doc) -> @@ -237,7 +260,7 @@ wrap(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"wrap"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}}, @@ -251,7 +274,6 @@ wrap(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format(filename:join(Privdir, atom_to_list(Node)++"-wrap.*.wrp")), ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, @@ -280,6 +302,9 @@ wrap(Config) when is_list(Config) -> end_of_trace] = flush(), ok. +wrap(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + wrap_merge(suite) -> []; wrap_merge(doc) -> @@ -289,7 +314,7 @@ wrap_merge(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"wrap_merge"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}}, @@ -303,7 +328,6 @@ wrap_merge(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-wrap_merge.*.wrp"), @@ -318,6 +342,9 @@ wrap_merge(Config) when is_list(Config) -> end_of_trace] = flush(), ok. +wrap_merge(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + wrap_merge_fetch_format(suite) -> []; @@ -328,7 +355,7 @@ wrap_merge_fetch_format(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"wrap_merge_fetch_format"), %% I'm setting priv_dir as cwd, so ttb_upload directory is created there @@ -348,7 +375,6 @@ wrap_merge_fetch_format(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([format]), - ?line ?t:stop_node(OtherNode), ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, @@ -360,6 +386,8 @@ wrap_merge_fetch_format(Config) when is_list(Config) -> ?line ok = file:set_cwd(Cwd), ok. +wrap_merge_fetch_format(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). write_config1(suite) -> []; @@ -371,7 +399,7 @@ write_config1(Config) when is_list(Config) -> ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"write_config1"), ?line ok = ttb:write_config(File, [{ttb,tracer,[[Node,OtherNode], @@ -384,7 +412,6 @@ write_config1(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config1"), @@ -410,6 +437,10 @@ write_config1(Config) when is_list(Config) -> end, ok. + +write_config1(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + write_config2(suite) -> []; write_config2(doc) -> @@ -419,7 +450,7 @@ write_config2(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"write_config2"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, @@ -433,7 +464,6 @@ write_config2(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config2"), @@ -459,6 +489,10 @@ write_config2(Config) when is_list(Config) -> end, ok. +write_config2(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + + write_config3(suite) -> []; write_config3(doc) -> @@ -468,7 +502,7 @@ write_config3(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"write_config3"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, @@ -496,7 +530,6 @@ write_config3(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config3"), @@ -522,6 +555,10 @@ write_config3(Config) when is_list(Config) -> end, ok. +write_config3(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + + history(suite) -> []; @@ -534,7 +571,7 @@ history(Config) when is_list(Config) -> ?line S = self(), ?line Nodes = [Node,OtherNode], - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"history"), ?line StartOpts = [{file, File}, {handler,{fun myhandler/4, S}}], @@ -552,14 +589,15 @@ history(Config) when is_list(Config) -> ?line ok = ttb:run_history([3,4]), ?line ?MODULE:foo(), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir,atom_to_list(Node)++"-history"), filename:join(Privdir,atom_to_list(OtherNode)++"-history")]), ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), ok. - + +history(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). write_trace_info(suite) -> @@ -571,7 +609,7 @@ write_trace_info(Config) when is_list(Config) -> ?line {ok,OtherNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"write_trace_info"), ?line {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, @@ -582,7 +620,6 @@ write_trace_info(Config) when is_list(Config) -> ?line ?MODULE:foo(), ?line rpc:call(OtherNode,?MODULE,foo,[]), ?line ttb:stop([nofetch]), - ?line ?t:stop_node(OtherNode), ?line ok = ttb:format( [filename:join(Privdir,atom_to_list(Node)++"-write_trace_info"), filename:join(Privdir, @@ -594,6 +631,9 @@ write_trace_info(Config) when is_list(Config) -> ok. +write_trace_info(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + seq_trace(suite) -> []; @@ -602,7 +642,7 @@ seq_trace(doc) -> seq_trace(Config) when is_list(Config) -> ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"seq_trace"), ?line {ok,[Node]} = ttb:tracer(node(),[{file,File}, {handler,{fun myhandler/4, S}}]), @@ -669,7 +709,7 @@ diskless(Config) when is_list(Config) -> ?line {ok,RemoteNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"diskless"), ?line {ok,[RemoteNode]} = ttb:tracer([RemoteNode],[{file, {local, File}}, @@ -680,7 +720,6 @@ diskless(Config) when is_list(Config) -> ?line rpc:call(RemoteNode,?MODULE,foo,[]), ?line timer:sleep(500), % needed for the IP port to flush ?line ttb:stop([nofetch]), - ?line ?t:stop_node(RemoteNode), ?line ok = ttb:format(filename:join(Privdir, atom_to_list(RemoteNode)++"-diskless")), @@ -688,6 +727,9 @@ diskless(Config) when is_list(Config) -> end_of_trace] = flush(), ok. +diskless(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + diskless_wrap(suite) -> []; diskless_wrap(doc) -> @@ -696,7 +738,7 @@ diskless_wrap(Config) when is_list(Config) -> ?line {ok,RemoteNode} = ?t:start_node(node2,slave,[]), ?line c:nl(?MODULE), ?line S = self(), - ?line Privdir=?config(priv_dir, Config), + ?line Privdir=priv_dir(Config), ?line File = filename:join(Privdir,"diskless"), ?line {ok,[RemoteNode]} = ttb:tracer([RemoteNode],[{file, {local, {wrap,File,200,3}}}, @@ -707,7 +749,6 @@ diskless_wrap(Config) when is_list(Config) -> ?line rpc:call(RemoteNode,?MODULE,foo,[]), ?line timer:sleep(500), % needed for the IP port to flush ?line ttb:stop([nofetch]), - ?line ?t:stop_node(RemoteNode), ?line ok = ttb:format(filename:join(Privdir, atom_to_list(RemoteNode)++"-diskless.*.wrp")), @@ -715,6 +756,9 @@ diskless_wrap(Config) when is_list(Config) -> end_of_trace] = flush(), ok. +diskless_wrap(cleanup,_Config) -> + ?line ?t:stop_node(ttb_helper:get_node(node2)). + otp_4967_1(suite) -> []; otp_4967_1(doc) -> @@ -733,7 +777,7 @@ otp_4967_2(doc) -> ["OTP-4967: Trace message sent to {Name, Node}"]; otp_4967_2(Config) when is_list(Config) -> io:format("1: ~p",[now()]), - ?line Privdir = ?config(priv_dir,Config), + ?line Privdir = priv_dir(Config), io:format("2: ~p",[now()]), ?line File = filename:join(Privdir,"otp_4967"), io:format("3: ~p",[now()]), @@ -767,8 +811,6 @@ otp_4967_2(Config) when is_list(Config) -> ok. - - myhandler(_Fd,Trace,_,Relay) -> Relay ! Trace, Relay. @@ -872,6 +914,27 @@ start_client_and_server() -> ?line ttb_helper:clear(), {ServerNode, ClientNode}. +stop_client_and_server() -> + ClientNode = ttb_helper:get_node(client), + ServerNode = ttb_helper:get_node(server), + erlang:monitor_node(ClientNode,true), + erlang:monitor_node(ServerNode,true), + ?line ?t:stop_node(ClientNode), + ?line ?t:stop_node(ServerNode), + wait_for_client_and_server_stop(ClientNode,ServerNode). + +wait_for_client_and_server_stop(undefined,undefined) -> + ok; +wait_for_client_and_server_stop(ClientNode,ServerNode) -> + receive + {nodedown,ClientNode} -> + erlang:monitor_node(ClientNode,false), + wait_for_client_and_server_stop(undefined,ServerNode); + {nodedown,ServerNode} -> + erlang:monitor_node(ServerNode,false), + wait_for_client_and_server_stop(ClientNode,undefined) + end. + begin_trace(ServerNode, ClientNode, Dest) -> ?line {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, Dest}]), @@ -912,10 +975,12 @@ fetch_when_no_option_given(Config) when is_list(Config) -> begin_trace(ServerNode, ClientNode, ?FNAME), ?line ttb_helper:msgs(4), ?line stopped = ttb:stop(), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line [_] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")). +fetch_when_no_option_given(cleanup,_Config) -> + ?line stop_client_and_server(). + + basic_ttb_run_ip_port(suite) -> []; basic_ttb_run_ip_port(doc) -> @@ -924,9 +989,9 @@ basic_ttb_run_ip_port(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line check_size(1, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(10, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line check_size(10, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode). +basic_ttb_run_ip_port(cleanup,_Config) -> + ?line stop_client_and_server(). basic_ttb_run_file_port(suite) -> []; @@ -936,9 +1001,9 @@ basic_ttb_run_file_port(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line check_size(1, ?FNAME, ?OUTPUT, ServerNode, ClientNode), ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(10, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line check_size(10, ?FNAME, ?OUTPUT, ServerNode, ClientNode). +basic_ttb_run_file_port(cleanup,_Config) -> + ?line stop_client_and_server(). return_fetch_dir_implies_fetch(suite) -> []; @@ -948,9 +1013,9 @@ return_fetch_dir_implies_fetch(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace(ServerNode, ClientNode, ?FNAME), ?line ttb_helper:msgs(2), - ?line {_,_} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line {_,_} = ttb:stop([return_fetch_dir]). +return_fetch_dir_implies_fetch(cleanup,_Config) -> + ?line stop_client_and_server(). logfile_name_in_fetch_dir(suite) -> []; @@ -960,11 +1025,11 @@ logfile_name_in_fetch_dir(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}), ?line {_,Dir} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line P1 = lists:nth(3, string:tokens(filename:basename(Dir), "_")), ?line P2 = hd(string:tokens(P1, "-")), ?line _File = P2. +logfile_name_in_fetch_dir(cleanup,_Config) -> + ?line stop_client_and_server(). upload_to_my_logdir(suite) -> []; @@ -975,10 +1040,10 @@ upload_to_my_logdir(Config) when is_list(Config) -> ?line {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), ?line {stopped,_} = ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line true = filelib:is_file(?DIRNAME), ?line [] = filelib:wildcard("ttb_upload_"++?FNAME). +upload_to_my_logdir(cleanup,_Config) -> + ?line stop_client_and_server(). upload_to_my_existing_logdir(suite) -> []; @@ -990,9 +1055,9 @@ upload_to_my_existing_logdir(Config) when is_list(Config) -> ?line {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), ?line {error,_,_} = (catch ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}])), - ?line {stopped,_} = ttb:stop(return_fetch_dir), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line {stopped,_} = ttb:stop(return_fetch_dir). +upload_to_my_existing_logdir(cleanup,_Config) -> + ?line stop_client_and_server(). fetch_with_options_not_as_list(suite) -> []; @@ -1003,11 +1068,11 @@ fetch_with_options_not_as_list(Config) when is_list(Config) -> ?line {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), ?line {stopped, D} = ttb:stop(return_fetch_dir), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line false = filelib:is_file(?OUTPUT), ?line ttb:format(D, {out, ?OUTPUT}), ?line true = filelib:is_file(?OUTPUT). +fetch_with_options_not_as_list(cleanup,_Config) -> + ?line stop_client_and_server(). error_when_formatting_multiple_files_4393(suite) -> []; @@ -1018,11 +1083,11 @@ error_when_formatting_multiple_files_4393(Config) when is_list(Config) -> ?line begin_trace(ServerNode, ClientNode, ?FNAME), ?line ttb_helper:msgs(2), ?line {_, Dir} = ttb:stop(return_fetch_dir), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), - ?line Files = [filename:join(Dir, atom_to_list(ttb_helper:get_node(server)) ++ "-" ++ ?FNAME), - filename:join(Dir, atom_to_list(ttb_helper:get_node(client)) ++ "-" ++ ?FNAME)], + ?line Files = [filename:join(Dir, atom_to_list(ServerNode) ++ "-" ++ ?FNAME), + filename:join(Dir, atom_to_list(ClientNode) ++ "-" ++ ?FNAME)], ?line ok = ttb:format(Files). +error_when_formatting_multiple_files_4393(cleanup,_Config) -> + ?line stop_client_and_server(). format_on_trace_stop(suite) -> []; @@ -1034,10 +1099,10 @@ format_on_trace_stop(Config) when is_list(Config) -> ?line ttb_helper:msgs_ip(2), ?line file:delete("HANDLER_OK"), ?line {_,_} = ttb:stop([fetch, return_fetch_dir, {format, {handler, marking_call_handler()}}]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line true = filelib:is_file("HANDLER_OK"), ?line ok = file:delete("HANDLER_OK"). +format_on_trace_stop(cleanup,_Config) -> + ?line stop_client_and_server(). %% The following three tests are for the issue "fixes fetch fail when nodes on the same host %% have different cwd" @@ -1050,9 +1115,9 @@ trace_to_remote_files_on_localhost_with_different_pwd(Config) when is_list(Confi ?line ok = file:set_cwd(".."), ?line {ServerNode, ClientNode} = start_client_and_server(), ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ok = file:set_cwd(OldDir). +trace_to_remote_files_on_localhost_with_different_pwd(cleanup,_Config) -> + ?line stop_client_and_server(). trace_to_local_files_on_localhost_with_different_pwd(suite) -> []; @@ -1063,9 +1128,9 @@ trace_to_local_files_on_localhost_with_different_pwd(Config) when is_list(Config ?line ok = file:set_cwd(".."), ?line {ServerNode, ClientNode} = start_client_and_server(), ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ok = file:set_cwd(OldDir). +trace_to_local_files_on_localhost_with_different_pwd(cleanup,_Config) -> + ?line stop_client_and_server(). trace_to_remote_files_on_localhost_with_different_pwd_abs(suite) -> []; @@ -1078,9 +1143,9 @@ trace_to_remote_files_on_localhost_with_different_pwd_abs(Config) when is_list(C ?line {ServerNode, ClientNode} = start_client_and_server(), ?line File = filename:join(Path, ?FNAME), ?line check_size(2, File, ?OUTPUT, ServerNode, ClientNode), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ok = file:set_cwd(OldDir). +trace_to_remote_files_on_localhost_with_different_pwd_abs(cleanup,_Config) -> + ?line stop_client_and_server(). %% Trace is not affected by changes of cwd on control node or remote nodes during tracing %% (three tests) @@ -1100,9 +1165,9 @@ changing_cwd_on_control_node(Config) when is_list(Config) -> ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line true = (2*(NumMsgs + 1) == length(Ret)), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ok = file:set_cwd(OldDir). +changing_cwd_on_control_node(cleanup,_Config) -> + ?line stop_client_and_server(). changing_cwd_on_control_node_with_local_trace(suite) -> []; @@ -1120,9 +1185,9 @@ changing_cwd_on_control_node_with_local_trace(Config) when is_list(Config) -> ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line true = (2*(NumMsgs + 1) == length(Ret)), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ok = file:set_cwd(OldDir). +changing_cwd_on_control_node_with_local_trace(cleanup,_Config) -> + ?line stop_client_and_server(). changing_cwd_on_remote_node(suite) -> []; @@ -1138,9 +1203,9 @@ changing_cwd_on_remote_node(Config) when is_list(Config) -> ?line {_, D} = ttb:stop([fetch, return_fetch_dir]), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), ?line {ok, Ret} = file:consult(?OUTPUT), - ?line true = (2*(NumMsgs + 1) == length(Ret)), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line true = (2*(NumMsgs + 1) == length(Ret)). +changing_cwd_on_remote_node(cleanup,_Config) -> + ?line stop_client_and_server(). one_command_trace_setup(suite) -> []; @@ -1148,19 +1213,19 @@ one_command_trace_setup(doc) -> ["One command trace setup"]; one_command_trace_setup(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line ttb:start_trace([ttb_helper:get_node(client), ttb_helper:get_node(server)], - [{server, received, '_', []}, - {client, put, 1, []}, - {client, get, '_', []}], - {all, call}, - [{file, ?FNAME}]), + ?line ttb:start_trace([ClientNode, ServerNode], + [{server, received, '_', []}, + {client, put, 1, []}, + {client, get, '_', []}], + {all, call}, + [{file, ?FNAME}]), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop(return_fetch_dir), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line 5 = length(Ret). +one_command_trace_setup(cleanup,_Config) -> + ?line stop_client_and_server(). dbg_style_fetch(suite) -> []; @@ -1169,12 +1234,12 @@ dbg_style_fetch(doc) -> dbg_style_fetch(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line DirSize = length(element(2, file:list_dir("."))), - ?line ttb:start_trace([ttb_helper:get_node(client), ttb_helper:get_node(server)], - [{server, received, '_', []}, - {client, put, 1, []}, - {client, get, '_', []}], - {all, call}, - [{shell, only}]), + ?line ttb:start_trace([ClientNode, ServerNode], + [{server, received, '_', []}, + {client, put, 1, []}, + {client, get, '_', []}], + {all, call}, + [{shell, only}]), ?line DirSize = length(element(2, file:list_dir("."))), ?line ttb_helper:msgs(2), ?line DirSize = length(element(2, file:list_dir("."))), @@ -1182,15 +1247,15 @@ dbg_style_fetch(Config) when is_list(Config) -> %%+1 -> ttb_last_trace ?line true = (DirSize + 1 == length(element(2, file:list_dir(".")))), ?line {ok,[{all, [{matched,_,_}, {matched,_,_}]}]} = - ttb:start_trace([ttb_helper:get_node(client), ttb_helper:get_node(server)], + ttb:start_trace([ClientNode, ServerNode], [{server, received, '_', []}, - {client, put, 1, []}, - {client, get, '_', []}], + {client, put, 1, []}, + {client, get, '_', []}], {all, call}, [{shell, only}]), - ?line ttb:stop(), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line ttb:stop(). +dbg_style_fetch(cleanup,_Config) -> + ?line stop_client_and_server(). shell_tracing_init(suite) -> []; @@ -1198,19 +1263,19 @@ shell_tracing_init(doc) -> ["Shell tracing init"]; shell_tracing_init(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line ttb:tracer([ttb_helper:get_node(client), ttb_helper:get_node(server)], shell), + ?line ttb:tracer([ClientNode, ServerNode], shell), ?line ttb:stop(), - ?line ttb:tracer([ttb_helper:get_node(client), ttb_helper:get_node(server)], + ?line ttb:tracer([ClientNode, ServerNode], [{file, {local, ?FNAME}}, shell]), ?line ttb:stop(), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), - ?line local_client_required_on_shell_tracing = try ttb:tracer([ttb_helper:get_node(client), ttb_helper:get_node(server)], - [{file, ?FNAME}, shell]) - catch - exit:local_client_required_on_shell_tracing -> - local_client_required_on_shell_tracing - end. + ?line local_client_required_on_shell_tracing = + try ttb:tracer([ClientNode, ServerNode],[{file, ?FNAME}, shell]) + catch + exit:local_client_required_on_shell_tracing -> + local_client_required_on_shell_tracing + end. +shell_tracing_init(cleanup,_Config) -> + ?line stop_client_and_server(). only_one_state_for_format_handler(suite) -> []; @@ -1221,11 +1286,11 @@ only_one_state_for_format_handler(Config) when is_list(Config) -> ?line begin_trace_local(ServerNode, ClientNode, ?FNAME), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, counter_call_handler()}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line [5] = Ret. +only_one_state_for_format_handler(cleanup,_Config) -> + ?line stop_client_and_server(). only_one_state_with_default_format_handler(suite) -> []; @@ -1236,10 +1301,10 @@ only_one_state_with_default_format_handler(Config) when is_list(Config) -> ?line begin_trace_local(ServerNode, ClientNode, ?FNAME), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}]), ?line true = filelib:is_file(?OUTPUT). +only_one_state_with_default_format_handler(cleanup,_Config) -> + ?line stop_client_and_server(). only_one_state_with_initial_format_handler(suite) -> []; @@ -1255,11 +1320,11 @@ only_one_state_with_initial_format_handler(Config) when is_list(Config) -> ?line ttb:tpl(client, get, []), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line [5] = Ret. +only_one_state_with_initial_format_handler(cleanup,_Config) -> + ?line stop_client_and_server(). run_trace_with_shortcut(Shortcut, Ret, F) -> ?line {ServerNode, ClientNode} = start_client_and_server(), @@ -1271,8 +1336,7 @@ run_trace_with_shortcut(Shortcut, Ret, F) -> ?line {_, D} = ttb:stop([return_fetch_dir]), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler()}]), ?line {ok, Ret} =file:consult(?OUTPUT), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line stop_client_and_server(). fun_for(return) -> {codestr, "fun(_) -> return_trace() end"}; @@ -1286,6 +1350,8 @@ run_trace_with_shortcut1(doc) -> run_trace_with_shortcut1(Config) when is_list(Config) -> ?line run_trace_with_shortcut(caller, [ok,ok], tp), ?line run_trace_with_shortcut(caller, [ok,ok], tpl). +run_trace_with_shortcut1(cleanup,_Config) -> + ?line stop_client_and_server(). run_trace_with_shortcut2(suite) -> []; @@ -1294,6 +1360,8 @@ run_trace_with_shortcut2(doc) -> run_trace_with_shortcut2(Config) when is_list(Config) -> ?line run_trace_with_shortcut(return, [ok,ok], tp), ?line run_trace_with_shortcut(return, [ok,ok], tpl). +run_trace_with_shortcut2(cleanup,_Config) -> + ?line stop_client_and_server(). run_trace_with_shortcut3(suite) -> []; @@ -1302,6 +1370,8 @@ run_trace_with_shortcut3(doc) -> run_trace_with_shortcut3(Config) when is_list(Config) -> ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tp), ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tpl). +run_trace_with_shortcut3(cleanup,_Config) -> + ?line stop_client_and_server(). run_trace_with_shortcut4(suite) -> []; @@ -1310,6 +1380,8 @@ run_trace_with_shortcut4(doc) -> run_trace_with_shortcut4(Config) when is_list(Config) -> ?line run_trace_with_shortcut(fun_for(msg_false), [], tp), ?line run_trace_with_shortcut(fun_for(msg_false), [], tpl). +run_trace_with_shortcut4(cleanup,_Config) -> + ?line stop_client_and_server(). cant_specify_local_and_flush(suite) -> []; @@ -1317,13 +1389,15 @@ cant_specify_local_and_flush(doc) -> ["Can't specify local and flush"]; cant_specify_local_and_flush(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line flush_unsupported_with_ip_trace_port = try ttb:tracer([ServerNode, ClientNode], [{flush, 1000}, {file, {local, ?FNAME}}]) - catch - exit:flush_unsupported_with_ip_trace_port -> - flush_unsupported_with_ip_trace_port - end, - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode). + ?line flush_unsupported_with_ip_trace_port = + try ttb:tracer([ServerNode, ClientNode], + [{flush, 1000}, {file, {local, ?FNAME}}]) + catch + exit:flush_unsupported_with_ip_trace_port -> + flush_unsupported_with_ip_trace_port + end. +cant_specify_local_and_flush(cleanup,_Config) -> + ?line stop_client_and_server(). trace_sorted_by_default(suite) -> []; @@ -1334,11 +1408,11 @@ trace_sorted_by_default(Config) when is_list(Config) -> ?line begin_trace_local(ServerNode, ClientNode, ?FILE), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, false}]), {ok, Ret} = file:consult(?OUTPUT), ?line [ClientNode,ServerNode,ClientNode,ServerNode,ServerNode] = Ret. +trace_sorted_by_default(cleanup,_Config) -> + ?line stop_client_and_server(). disable_sorting(suite) -> []; @@ -1349,11 +1423,11 @@ disable_sorting(Config) when is_list(Config) -> ?line begin_trace_local(ServerNode, ClientNode, ?FILE), ?line ttb_helper:msgs(2), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ServerNode), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, true}]), {ok, Ret} = file:consult(?OUTPUT), ?line [ClientNode,ClientNode,ServerNode,ServerNode,ServerNode] = Ret. +disable_sorting(cleanup,_Config) -> + ?line stop_client_and_server(). %% ----------------------------------------------------------------------------- %% tests for autoresume of tracing @@ -1367,6 +1441,8 @@ trace_resumed_after_node_restart(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace_with_resume(ServerNode, ClientNode, ?FNAME), ?line logic(2,6,file). +trace_resumed_after_node_restart(cleanup,_Config) -> + ?line stop_client_and_server(). trace_resumed_after_node_restart_ip(suite) -> []; @@ -1376,6 +1452,8 @@ trace_resumed_after_node_restart_ip(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace_with_resume(ServerNode, ClientNode, {local, ?FNAME}), ?line logic(2,6,local). +trace_resumed_after_node_restart_ip(cleanup,_Config) -> + ?line stop_client_and_server(). trace_resumed_after_node_restart_wrap(suite) -> []; @@ -1385,6 +1463,8 @@ trace_resumed_after_node_restart_wrap(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), ?line logic(1,4,file). +trace_resumed_after_node_restart_wrap(cleanup,_Config) -> + ?line stop_client_and_server(). trace_resumed_after_node_restart_wrap_mult(suite) -> []; @@ -1394,18 +1474,18 @@ trace_resumed_after_node_restart_wrap_mult(Config) when is_list(Config) -> ?line {ServerNode, ClientNode} = start_client_and_server(), ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), ?line logic(20,8,file). +trace_resumed_after_node_restart_wrap_mult(cleanup,_Config) -> + ?line stop_client_and_server(). logic(N, M, TracingType) -> helper_msgs(N, TracingType), ?t:stop_node(ttb_helper:get_node(client)), timer:sleep(2500), - ?line {ok,ClientNode} = ?t:start_node(client,slave,[]), + ?line {ok,_ClientNode} = ?t:start_node(client,slave,[]), ?line ok = ttb_helper:c(code, add_paths, [code:get_path()]), ?line ttb_helper:c(client, init, []), ?line helper_msgs(N, TracingType), ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ?t:stop_node(ttb_helper:get_node(server)), - ?line ?t:stop_node(ClientNode), ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler2()}]), ?line {ok, Ret} = file:consult(?OUTPUT), ?line M = length(Ret). @@ -1428,3 +1508,27 @@ helper_msgs(N, TracingType) -> _ -> ttb_helper:msgs(N) end. + +priv_dir(Conf) -> + %% Due to problem with long paths on windows => creating a new + %% priv_dir under data_dir + Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)), + filelib:ensure_dir(filename:join(Dir,"*")), + Dir. + +clean_priv_dir(Config) -> + PrivDir = priv_dir(Config), + case filelib:is_dir(PrivDir) of + true -> rm(PrivDir); + false -> ok + end. + +rm(This) -> + case filelib:is_dir(This) of + true -> + {ok,Files} = file:list_dir(This), + [rm(filename:join(This,F)) || F <- Files], + file:del_dir(This); + false -> + file:delete(This) + end. diff --git a/lib/observer/test/ttb_helper.erl b/lib/observer/test/ttb_helper.erl index 19fdc0e159..76b06cd3ce 100644 --- a/lib/observer/test/ttb_helper.erl +++ b/lib/observer/test/ttb_helper.erl @@ -70,7 +70,7 @@ msgs(N) -> msgs_ip(N) -> [c(client, put, [test_msg]) || _ <- lists:seq(1, N)], s(server, received, [a,b]), - timer:sleep(100). %% allow trace messages to arrive over tcp/ip + timer:sleep(200). %% allow trace messages to arrive over tcp/ip run() -> ttb({local, "A"}), diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile index e2f09733d0..3e648d854d 100644 --- a/lib/odbc/doc/src/Makefile +++ b/lib/odbc/doc/src/Makefile @@ -29,14 +29,6 @@ VSN=$(ODBC_VSN) APPLICATION=odbc # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -89,32 +81,10 @@ EXTRA_FILES = $(DEFAULT_GIF_FILES) \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -128,8 +98,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif # Copy them to ../html $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -144,32 +112,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) # We depend just to copy them to ../html @@ -182,8 +124,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -193,32 +133,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif release_spec: - - - - diff --git a/lib/odbc/doc/src/make.dep b/lib/odbc/doc/src/make.dep deleted file mode 100644 index d62e8dd8f0..0000000000 --- a/lib/odbc/doc/src/make.dep +++ /dev/null @@ -1,27 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex databases.tex error_handling.tex \ - getting_started.tex introduction.tex odbc.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: odbc_app_arc.ps - diff --git a/lib/odbc/src/odbc.appup.src b/lib/odbc/src/odbc.appup.src index f3a3af8c29..853323da09 100644 --- a/lib/odbc/src/odbc.appup.src +++ b/lib/odbc/src/odbc.appup.src @@ -1,10 +1,12 @@ %% -*- erlang -*- {"%VSN%", [ + {"2.10.11", [{restart_application, odbc}]}, {"2.10.10", [{restart_application, odbc}]}, {"2.10.9", [{restart_application, odbc}]} ], [ + {"2.10.11", [{restart_application, odbc}]}, {"2.10.10", [{restart_application, odbc}]}, {"2.10.9", [{restart_application, odbc}]} ]}. diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl index 68497292db..36afd1abcf 100644 --- a/lib/odbc/src/odbc.erl +++ b/lib/odbc/src/odbc.erl @@ -748,6 +748,9 @@ handle_info({'DOWN', _Ref, _Type, _Process, normal}, State) -> handle_info({'DOWN', _Ref, _Type, _Process, timeout}, State) -> {stop, normal, State#state{reply_to = undefined}}; + +handle_info({'DOWN', _Ref, _Type, _Process, shutdown}, State) -> + {stop, normal, State#state{reply_to = undefined}}; handle_info({'DOWN', _Ref, _Type, Process, Reason}, State) -> {stop, {stopped, {'EXIT', Process, Reason}}, diff --git a/lib/orber/doc/src/Makefile b/lib/orber/doc/src/Makefile index b8e26d5ba3..8a555cb408 100644 --- a/lib/orber/doc/src/Makefile +++ b/lib/orber/doc/src/Makefile @@ -28,14 +28,6 @@ VSN=$(ORBER_VSN) APPLICATION=orber # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -128,32 +120,10 @@ EXTRA_FILES = summary.html.src \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -167,8 +137,6 @@ $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -184,35 +152,6 @@ clean clean_docs: rm -f errs core *~ rm -f $(JD_HTML) $(JD_PACK) -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(INTERNAL_HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTMLDIR)/* - rm -f $(MAN3DIR)/* - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - rm -f $(JD_HTML) $(JD_PACK) - -endif - - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -224,9 +163,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk - -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -236,30 +172,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - -endif -endif - -endif release_spec: - diff --git a/lib/orber/doc/src/make.dep b/lib/orber/doc/src/make.dep deleted file mode 100644 index cf5aad747d..0000000000 --- a/lib/orber/doc/src/make.dep +++ /dev/null @@ -1,62 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: CosNaming.tex CosNaming_BindingIterator.tex \ - CosNaming_NamingContext.tex CosNaming_NamingContextExt.tex \ - Module_Interface.tex any.tex book.tex ch_contents.tex \ - ch_debugging.tex ch_exceptions.tex \ - ch_idl_to_erlang_mapping.tex ch_ifr.tex ch_install.tex \ - ch_interceptors.tex ch_introduction.tex ch_naming_service.tex \ - ch_orber_kernel.tex ch_orberweb.tex ch_security.tex \ - ch_stubs.tex corba.tex corba_object.tex example_part.tex \ - fixed.tex interceptors.tex intro_part.tex \ - lname.tex lname_component.tex orber.tex orber_acl.tex \ - orber_diagnostics.tex orber_ifr.tex orber_tc.tex \ - ref_man.tex tools_debugging_part.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -ch_contents.tex: ../../../../system/doc/definitions/term.defs - -ch_idl_to_erlang_mapping.tex: ../../../../system/doc/definitions/term.defs - -ch_install.tex: ../../../../system/doc/definitions/term.defs - -ch_introduction.tex: ../../../../system/doc/definitions/term.defs - -ch_naming_service.tex: ../../../../system/doc/definitions/term.defs - -ch_orber_kernel.tex: ../../../../system/doc/definitions/term.defs - -orber_ifr.tex: ../../../../system/doc/definitions/term.defs - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: firewall_nat.ps - -book.dvi: interceptor_operations.ps - -book.dvi: dependent.ps orbs.ps - -book.dvi: name.ps - -book.dvi: iiop.ps theORB.ps - -book.dvi: dataframe1.ps dataframe2.ps dataframe3.ps \ - dataframe4.ps dataframe5.ps dataframe6.ps \ - dataframe7.ps dataframe8.ps menuframe.ps - diff --git a/lib/orber/priv/Makefile b/lib/orber/priv/Makefile index 2847727035..2847727035 100755..100644 --- a/lib/orber/priv/Makefile +++ b/lib/orber/priv/Makefile diff --git a/lib/orber/priv/blank.html b/lib/orber/priv/blank.html index 44e86908a0..44e86908a0 100755..100644 --- a/lib/orber/priv/blank.html +++ b/lib/orber/priv/blank.html diff --git a/lib/orber/priv/info_frames.html b/lib/orber/priv/info_frames.html index 75456a67a4..75456a67a4 100755..100644 --- a/lib/orber/priv/info_frames.html +++ b/lib/orber/priv/info_frames.html diff --git a/lib/orber/priv/main_frame.html b/lib/orber/priv/main_frame.html index 056a92812e..056a92812e 100755..100644 --- a/lib/orber/priv/main_frame.html +++ b/lib/orber/priv/main_frame.html diff --git a/lib/orber/priv/orber.tool b/lib/orber/priv/orber.tool index 910a7d7e45..910a7d7e45 100755..100644 --- a/lib/orber/priv/orber.tool +++ b/lib/orber/priv/orber.tool diff --git a/lib/orber/priv/orber_help.txt b/lib/orber/priv/orber_help.txt index a6580dc30a..a6580dc30a 100755..100644 --- a/lib/orber/priv/orber_help.txt +++ b/lib/orber/priv/orber_help.txt diff --git a/lib/orber/priv/start_info.html b/lib/orber/priv/start_info.html index 0ad521c90a..0ad521c90a 100755..100644 --- a/lib/orber/priv/start_info.html +++ b/lib/orber/priv/start_info.html diff --git a/lib/orber/test/csiv2_SUITE.erl b/lib/orber/test/csiv2_SUITE.erl index 95cd8c56b3..406a8ea693 100644 --- a/lib/orber/test/csiv2_SUITE.erl +++ b/lib/orber/test/csiv2_SUITE.erl @@ -696,7 +696,6 @@ ssl_client_peercert_api(_Config) -> ?match({ok,_,_}, orber_test_lib:js_node(Options)), crypto:start(), ssl:start(), - ssl:seed("testing"), SSLOptions = orber_test_lib:get_options(ssl, server), {ok, LSock} = ?match({ok, _}, ssl:listen(0, SSLOptions)), {ok, {_Address, LPort}} = ?match({ok, {_, _}}, ssl:sockname(LSock)), @@ -857,8 +856,7 @@ fake_server_ORB(Type, Port, Options, Action, Data) -> start_ssl(ssl) -> crypto:start(), - ssl:start(), - ssl:seed("testing"); + ssl:start(); start_ssl(_) -> ok. diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl index 608fb23f3e..b9453663c3 100644 --- a/lib/orber/test/multi_ORB_SUITE.erl +++ b/lib/orber/test/multi_ORB_SUITE.erl @@ -1683,7 +1683,6 @@ ssl_reconfigure(ExtraSSLOptions) -> {ip_address, IP}|ExtraSSLOptions])), orber_test_lib:remote_apply(ServerNode, ssl, start, []), orber_test_lib:remote_apply(ServerNode, crypto, start, []), - orber_test_lib:remote_apply(ServerNode, ssl, seed, ["testing"]), ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib, install_test_data, [ssl])), @@ -1713,7 +1712,6 @@ ssl_reconfigure(ExtraSSLOptions) -> [ssl])), orber_test_lib:remote_apply(ClientNode, ssl, start, []), orber_test_lib:remote_apply(ServerNode, crypto, start, []), - orber_test_lib:remote_apply(ClientNode, ssl, seed, ["testing"]), Obj = ?match(#'IOP_IOR'{}, orber_test_lib:remote_apply(ClientNode, corba, string_to_object, ["corbaname:iiop:1.1@"++Loopback++":5648/NameService#mamba", diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl index ffc13d0e3c..903ab1d771 100644 --- a/lib/orber/test/orber_test_lib.erl +++ b/lib/orber/test/orber_test_lib.erl @@ -296,8 +296,7 @@ slave_sup() -> start_ssl(true, Node) -> rpc:call(Node, ssl, start, []), - rpc:call(Node, crypto, start, []), - rpc:call(Node, ssl, seed, ["testing"]); + rpc:call(Node, crypto, start, []); start_ssl(_, _) -> ok. diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 29b21e8e01..0eac1e1410 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,3 +1,3 @@ -ORBER_VSN = 3.6.22 +ORBER_VSN = 3.6.23 diff --git a/lib/os_mon/doc/src/make.dep b/lib/os_mon/doc/src/make.dep deleted file mode 100644 index b657f2e036..0000000000 --- a/lib/os_mon/doc/src/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex cpu_sup.tex disksup.tex memsup.tex \ - nteventlog.tex os_mon.tex os_mon_mib.tex os_sup.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/otp_mibs/doc/src/make.dep b/lib/otp_mibs/doc/src/make.dep deleted file mode 100644 index 2885155315..0000000000 --- a/lib/otp_mibs/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex introduction.tex mibs.tex otp_mib.tex \ - part.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/parsetools/doc/src/make.dep b/lib/parsetools/doc/src/make.dep deleted file mode 100644 index 3a09ecdedd..0000000000 --- a/lib/parsetools/doc/src/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex leex.tex ref_man.tex yecc.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -ref_man.tex: ../../../../system/doc/definitions/term.defs - diff --git a/lib/percept/doc/src/make.dep b/lib/percept/doc/src/make.dep deleted file mode 100644 index df16cffd4f..0000000000 --- a/lib/percept/doc/src/make.dep +++ /dev/null @@ -1,34 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex egd.tex egd_ug.tex part.tex percept.tex \ - percept_profile.tex percept_ug.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -egd_ug.tex: img.erl img_esi.erl - -percept_ug.tex: sorter.erl - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: img_esi_result.ps test1.ps test2.ps test3.ps \ - test4.ps - -book.dvi: percept_compare.ps percept_overview.ps percept_processes.ps \ - percept_processinfo.ps - diff --git a/lib/percept/doc/src/part_notes.xml b/lib/percept/doc/src/part_notes.xml index 4965e67640..4965e67640 100755..100644 --- a/lib/percept/doc/src/part_notes.xml +++ b/lib/percept/doc/src/part_notes.xml diff --git a/lib/percept/test/percept_SUITE_data/ipc-dist.dat b/lib/percept/test/percept_SUITE_data/ipc-dist.dat Binary files differindex 14ab6c0c5d..14ab6c0c5d 100755..100644 --- a/lib/percept/test/percept_SUITE_data/ipc-dist.dat +++ b/lib/percept/test/percept_SUITE_data/ipc-dist.dat diff --git a/lib/pman/doc/src/make.dep b/lib/pman/doc/src/make.dep deleted file mode 100644 index 2f6a8a06cd..0000000000 --- a/lib/pman/doc/src/make.dep +++ /dev/null @@ -1,26 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex pman.tex pman_chapter.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: main_window.ps options.ps trace.ps - diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore new file mode 100644 index 0000000000..db24906676 --- /dev/null +++ b/lib/public_key/.gitignore @@ -0,0 +1,7 @@ +# public_key + +/lib/public_key/asn1/*.asn1db +/lib/public_key/asn1/*.erl +/lib/public_key/asn1/*.hrl +/lib/public_key/include/OTP-PUB-KEY.hrl +/lib/public_key/include/PKCS-FRAME.hrl diff --git a/lib/public_key/asn1/DSS.asn1 b/lib/public_key/asn1/DSS.asn1 index 77aca3808b..77aca3808b 100755..100644 --- a/lib/public_key/asn1/DSS.asn1 +++ b/lib/public_key/asn1/DSS.asn1 diff --git a/lib/public_key/asn1/InformationFramework.asn1 b/lib/public_key/asn1/InformationFramework.asn1 new file mode 100644 index 0000000000..40fbd11a2a --- /dev/null +++ b/lib/public_key/asn1/InformationFramework.asn1 @@ -0,0 +1,682 @@ +InformationFramework {joint-iso-itu-t ds(5) module(1) informationFramework(1) + 6} DEFINITIONS ::= +BEGIN + +-- EXPORTS All +-- The types and values defined in this module are exported for use in the other ASN.1 modules contained +-- within the Directory Specifications, and for the use of other applications which will use them to access +-- Directory services. Other applications may use them for their own purposes, but this will not constrain +-- extensions and modifications needed to maintain or improve the Directory service. +IMPORTS + -- from ITU-T Rec. X.501 | ISO/IEC 9594-2 + directoryAbstractService, id-ar, id-at, id-mr, id-nf, id-oa, id-oc, + id-sc, selectedAttributeTypes, serviceAdministration + FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1) + usefulDefinitions(0) 6} + SearchRule + FROM ServiceAdministration serviceAdministration + -- from ITU-T Rec. X.511 | ISO/IEC 9594-3 + TypeAndContextAssertion + FROM DirectoryAbstractService directoryAbstractService + -- from ITU-T Rec. X.520 | ISO/IEC 9594-6 + booleanMatch, commonName, generalizedTimeMatch, generalizedTimeOrderingMatch, + integerFirstComponentMatch, integerMatch, integerOrderingMatch, + objectIdentifierFirstComponentMatch, UnboundedDirectoryString + FROM SelectedAttributeTypes selectedAttributeTypes; + +-- attribute data types +Attribute{ATTRIBUTE:SupportedAttributes} ::= SEQUENCE { + type ATTRIBUTE.&id({SupportedAttributes}), + values + SET SIZE (0..MAX) OF ATTRIBUTE.&Type({SupportedAttributes}{@type}), + valuesWithContext + SET SIZE (1..MAX) OF + SEQUENCE {value ATTRIBUTE.&Type({SupportedAttributes}{@type}), + contextList SET SIZE (1..MAX) OF Context} OPTIONAL +} + +AttributeType ::= ATTRIBUTE.&id + +AttributeValue ::= ATTRIBUTE.&Type + +Context ::= SEQUENCE { + contextType CONTEXT.&id({SupportedContexts}), + contextValues + SET SIZE (1..MAX) OF CONTEXT.&Type({SupportedContexts}{@contextType}), + fallback BOOLEAN DEFAULT FALSE +} + +AttributeValueAssertion ::= SEQUENCE { + type ATTRIBUTE.&id({SupportedAttributes}), + assertion + ATTRIBUTE.&equality-match.&AssertionType + ({SupportedAttributes}{@type}), + assertedContexts + CHOICE {allContexts [0] NULL, + selectedContexts [1] SET SIZE (1..MAX) OF ContextAssertion + } OPTIONAL +} + +ContextAssertion ::= SEQUENCE { + contextType CONTEXT.&id({SupportedContexts}), + contextValues + SET SIZE (1..MAX) OF + CONTEXT.&Assertion({SupportedContexts}{@contextType}) +} + +AttributeTypeAssertion ::= SEQUENCE { + type ATTRIBUTE.&id({SupportedAttributes}), + assertedContexts SEQUENCE SIZE (1..MAX) OF ContextAssertion OPTIONAL +} + +-- Definition of the following information object set is deferred, perhaps to standardized +-- profiles or to protocol implementation conformance statements. The set is required to +-- specify a table constraint on the values component of Attribute, the value component +-- of AttributeTypeAndValue, and the assertion component of AttributeValueAssertion. +SupportedAttributes ATTRIBUTE ::= + {objectClass | aliasedEntryName, ...} + +-- Definition of the following information object set is deferred, perhaps to standardized +-- profiles or to protocol implementation conformance statements. The set is required to +-- specify a table constraint on the context specifications +SupportedContexts CONTEXT ::= + {...} + +-- naming data types +Name ::= CHOICE { -- only one possibility for now --rdnSequence RDNSequence +} + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +DistinguishedName ::= RDNSequence + +RelativeDistinguishedName ::= + SET SIZE (1..MAX) OF AttributeTypeAndDistinguishedValue + +AttributeTypeAndDistinguishedValue ::= SEQUENCE { + type ATTRIBUTE.&id({SupportedAttributes}), + value ATTRIBUTE.&Type({SupportedAttributes}{@type}), + primaryDistinguished BOOLEAN DEFAULT TRUE, + valuesWithContext + SET SIZE (1..MAX) OF + SEQUENCE {distingAttrValue + [0] ATTRIBUTE.&Type({SupportedAttributes}{@type}) + OPTIONAL, + contextList SET SIZE (1..MAX) OF Context} OPTIONAL +} + +-- subtree data types +SubtreeSpecification ::= SEQUENCE { + base [0] LocalName DEFAULT {}, + COMPONENTS OF ChopSpecification, + specificationFilter [4] Refinement OPTIONAL +} + +-- empty sequence specifies whole administrative area +LocalName ::= RDNSequence + +ChopSpecification ::= SEQUENCE { + specificExclusions + [1] SET SIZE (1..MAX) OF + CHOICE {chopBefore [0] LocalName, + chopAfter [1] LocalName} OPTIONAL, + minimum [2] BaseDistance DEFAULT 0, + maximum [3] BaseDistance OPTIONAL +} + +BaseDistance ::= INTEGER(0..MAX) + +Refinement ::= CHOICE { + item [0] OBJECT-CLASS.&id, + and [1] SET SIZE (1..MAX) OF Refinement, + or [2] SET SIZE (1..MAX) OF Refinement, + not [3] Refinement +} + +-- OBJECT-CLASS information object class specification +OBJECT-CLASS ::= CLASS { + &Superclasses OBJECT-CLASS OPTIONAL, + &kind ObjectClassKind DEFAULT structural, + &MandatoryAttributes ATTRIBUTE OPTIONAL, + &OptionalAttributes ATTRIBUTE OPTIONAL, + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + [SUBCLASS OF &Superclasses] + [KIND &kind] + [MUST CONTAIN &MandatoryAttributes] + [MAY CONTAIN &OptionalAttributes] + ID &id +} + +ObjectClassKind ::= ENUMERATED {abstract(0), structural(1), auxiliary(2)} + +-- object classes +top OBJECT-CLASS ::= { + KIND abstract + MUST CONTAIN {objectClass} + ID id-oc-top +} + +alias OBJECT-CLASS ::= { + SUBCLASS OF {top} + MUST CONTAIN {aliasedEntryName} + ID id-oc-alias +} + +parent OBJECT-CLASS ::= {KIND abstract + ID id-oc-parent +} + +child OBJECT-CLASS ::= {KIND auxiliary + ID id-oc-child +} + +-- ATTRIBUTE information object class specification +ATTRIBUTE ::= CLASS { + &derivation ATTRIBUTE OPTIONAL, + &Type OPTIONAL, -- either &Type or &derivation required + &equality-match MATCHING-RULE OPTIONAL, + &ordering-match MATCHING-RULE OPTIONAL, + &substrings-match MATCHING-RULE OPTIONAL, + &single-valued BOOLEAN DEFAULT FALSE, + &collective BOOLEAN DEFAULT FALSE, + &dummy BOOLEAN DEFAULT FALSE, + -- operational extensions + &no-user-modification BOOLEAN DEFAULT FALSE, + &usage AttributeUsage DEFAULT userApplications, + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + [SUBTYPE OF &derivation] + [WITH SYNTAX &Type] + [EQUALITY MATCHING RULE &equality-match] + [ORDERING MATCHING RULE &ordering-match] + [SUBSTRINGS MATCHING RULE &substrings-match] + [SINGLE VALUE &single-valued] + [COLLECTIVE &collective] + [DUMMY &dummy] + [NO USER MODIFICATION &no-user-modification] + [USAGE &usage] + ID &id +} + +AttributeUsage ::= ENUMERATED { + userApplications(0), directoryOperation(1), distributedOperation(2), + dSAOperation(3)} + +-- attributes +objectClass ATTRIBUTE ::= { + WITH SYNTAX OBJECT IDENTIFIER + EQUALITY MATCHING RULE objectIdentifierMatch + ID id-at-objectClass +} + +aliasedEntryName ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + ID id-at-aliasedEntryName +} + +-- MATCHING-RULE information object class specification +MATCHING-RULE ::= CLASS { + &ParentMatchingRules MATCHING-RULE OPTIONAL, + &AssertionType OPTIONAL, + &uniqueMatchIndicator ATTRIBUTE OPTIONAL, + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + [PARENT &ParentMatchingRules] + [SYNTAX &AssertionType] + [UNIQUE-MATCH-INDICATOR &uniqueMatchIndicator] + ID &id +} + +-- matching rules +objectIdentifierMatch MATCHING-RULE ::= { + SYNTAX OBJECT IDENTIFIER + ID id-mr-objectIdentifierMatch +} + +distinguishedNameMatch MATCHING-RULE ::= { + SYNTAX DistinguishedName + ID id-mr-distinguishedNameMatch +} + +MAPPING-BASED-MATCHING{SelectedBy, BOOLEAN:combinable, MappingResult, + OBJECT IDENTIFIER:matchingRule} ::= CLASS { + &selectBy SelectedBy OPTIONAL, + &ApplicableTo ATTRIBUTE, + &subtypesIncluded BOOLEAN DEFAULT TRUE, + &combinable BOOLEAN(combinable), + &mappingResults MappingResult OPTIONAL, + &userControl BOOLEAN DEFAULT FALSE, + &exclusive BOOLEAN DEFAULT TRUE, + &matching-rule MATCHING-RULE.&id(matchingRule), + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + [SELECT BY &selectBy] + APPLICABLE TO &ApplicableTo + [SUBTYPES INCLUDED &subtypesIncluded] + COMBINABLE &combinable + [MAPPING RESULTS &mappingResults] + [USER CONTROL &userControl] + [EXCLUSIVE &exclusive] + MATCHING RULE &matching-rule + ID &id +} + +-- NAME-FORM information object class specification +NAME-FORM ::= CLASS { + &namedObjectClass OBJECT-CLASS, + &MandatoryAttributes ATTRIBUTE, + &OptionalAttributes ATTRIBUTE OPTIONAL, + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + NAMES &namedObjectClass + WITH ATTRIBUTES &MandatoryAttributes + [AND OPTIONALLY &OptionalAttributes] + ID &id +} + +-- STRUCTURE-RULE class and DIT structure rule data types +DITStructureRule ::= SEQUENCE { + ruleIdentifier RuleIdentifier, + -- shall be unique within the scope of the subschema + nameForm NAME-FORM.&id, + superiorStructureRules SET SIZE (1..MAX) OF RuleIdentifier OPTIONAL +} + +RuleIdentifier ::= INTEGER + +STRUCTURE-RULE ::= CLASS { + &nameForm NAME-FORM, + &SuperiorStructureRules STRUCTURE-RULE OPTIONAL, + &id RuleIdentifier +} +WITH SYNTAX { + NAME FORM &nameForm + [SUPERIOR RULES &SuperiorStructureRules] + ID &id +} + +-- DIT content rule data type and CONTENT-RULE class +DITContentRule ::= SEQUENCE { + structuralObjectClass OBJECT-CLASS.&id, + auxiliaries SET SIZE (1..MAX) OF OBJECT-CLASS.&id OPTIONAL, + mandatory [1] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL, + optional [2] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL, + precluded [3] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL +} + +CONTENT-RULE ::= CLASS { + &structuralClass OBJECT-CLASS.&id UNIQUE, + &Auxiliaries OBJECT-CLASS OPTIONAL, + &Mandatory ATTRIBUTE OPTIONAL, + &Optional ATTRIBUTE OPTIONAL, + &Precluded ATTRIBUTE OPTIONAL +} +WITH SYNTAX { + STRUCTURAL OBJECT-CLASS &structuralClass + [AUXILIARY OBJECT-CLASSES &Auxiliaries] + [MUST CONTAIN &Mandatory] + [MAY CONTAIN &Optional] + [MUST-NOT CONTAIN &Precluded] +} + +CONTEXT ::= CLASS { + &Type , + &DefaultValue OPTIONAL, + &Assertion OPTIONAL, + &absentMatch BOOLEAN DEFAULT TRUE, + &id OBJECT IDENTIFIER UNIQUE +} +WITH SYNTAX { + WITH SYNTAX &Type + [DEFAULT-VALUE &DefaultValue] + [ASSERTED AS &Assertion] + [ABSENT-MATCH &absentMatch] + ID &id +} + +DITContextUse ::= SEQUENCE { + attributeType ATTRIBUTE.&id, + mandatoryContexts [1] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL, + optionalContexts [2] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL +} + +DIT-CONTEXT-USE-RULE ::= CLASS { + &attributeType ATTRIBUTE.&id UNIQUE, + &Mandatory CONTEXT OPTIONAL, + &Optional CONTEXT OPTIONAL +} +WITH SYNTAX { + ATTRIBUTE TYPE &attributeType + [MANDATORY CONTEXTS &Mandatory] + [OPTIONAL CONTEXTS &Optional] +} + +FRIENDS ::= CLASS { + &anchor ATTRIBUTE.&id UNIQUE, + &Friends ATTRIBUTE +}WITH SYNTAX {ANCHOR &anchor + FRIENDS &Friends +} + +-- system schema information objects +-- object classes +subentry OBJECT-CLASS ::= { + SUBCLASS OF {top} + KIND structural + MUST CONTAIN {commonName | subtreeSpecification} + ID id-sc-subentry +} + +subentryNameForm NAME-FORM ::= { + NAMES subentry + WITH ATTRIBUTES {commonName} + ID id-nf-subentryNameForm +} + +subtreeSpecification ATTRIBUTE ::= { + WITH SYNTAX SubtreeSpecification + USAGE directoryOperation + ID id-oa-subtreeSpecification +} + +administrativeRole ATTRIBUTE ::= { + WITH SYNTAX OBJECT-CLASS.&id + EQUALITY MATCHING RULE objectIdentifierMatch + USAGE directoryOperation + ID id-oa-administrativeRole +} + +createTimestamp ATTRIBUTE ::= { + WITH SYNTAX GeneralizedTime + -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1 + EQUALITY MATCHING RULE generalizedTimeMatch + ORDERING MATCHING RULE generalizedTimeOrderingMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-createTimestamp +} + +modifyTimestamp ATTRIBUTE ::= { + WITH SYNTAX GeneralizedTime + -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1 + EQUALITY MATCHING RULE generalizedTimeMatch + ORDERING MATCHING RULE generalizedTimeOrderingMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-modifyTimestamp +} + +subschemaTimestamp ATTRIBUTE ::= { + WITH SYNTAX GeneralizedTime + -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1 + EQUALITY MATCHING RULE generalizedTimeMatch + ORDERING MATCHING RULE generalizedTimeOrderingMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-subschemaTimestamp +} + +creatorsName ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-creatorsName +} + +modifiersName ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-modifiersName +} + +subschemaSubentryList ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-subschemaSubentryList +} + +accessControlSubentryList ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-accessControlSubentryList +} + +collectiveAttributeSubentryList ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-collectiveAttributeSubentryList +} + +contextDefaultSubentryList ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-contextDefaultSubentryList +} + +serviceAdminSubentryList ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-serviceAdminSubentryList +} + +hasSubordinates ATTRIBUTE ::= { + WITH SYNTAX BOOLEAN + EQUALITY MATCHING RULE booleanMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-hasSubordinates +} + +accessControlSubentry OBJECT-CLASS ::= { + KIND auxiliary + ID id-sc-accessControlSubentry +} + +collectiveAttributeSubentry OBJECT-CLASS ::= { + KIND auxiliary + ID id-sc-collectiveAttributeSubentry +} + +collectiveExclusions ATTRIBUTE ::= { + WITH SYNTAX OBJECT IDENTIFIER + EQUALITY MATCHING RULE objectIdentifierMatch + USAGE directoryOperation + ID id-oa-collectiveExclusions +} + +contextAssertionSubentry OBJECT-CLASS ::= { + KIND auxiliary + MUST CONTAIN {contextAssertionDefaults} + ID id-sc-contextAssertionSubentry +} + +contextAssertionDefaults ATTRIBUTE ::= { + WITH SYNTAX TypeAndContextAssertion + EQUALITY MATCHING RULE objectIdentifierFirstComponentMatch + USAGE directoryOperation + ID id-oa-contextAssertionDefault +} + +serviceAdminSubentry OBJECT-CLASS ::= { + KIND auxiliary + MUST CONTAIN {searchRules} + ID id-sc-serviceAdminSubentry +} + +searchRules ATTRIBUTE ::= { + WITH SYNTAX SearchRuleDescription + EQUALITY MATCHING RULE integerFirstComponentMatch + USAGE directoryOperation + ID id-oa-searchRules +} + +SearchRuleDescription ::= SEQUENCE { + COMPONENTS OF SearchRule, + name [28] SET SIZE (1..MAX) OF UnboundedDirectoryString OPTIONAL, + description [29] UnboundedDirectoryString OPTIONAL +} + +hierarchyLevel ATTRIBUTE ::= { + WITH SYNTAX HierarchyLevel + EQUALITY MATCHING RULE integerMatch + ORDERING MATCHING RULE integerOrderingMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-hierarchyLevel +} + +HierarchyLevel ::= INTEGER + +hierarchyBelow ATTRIBUTE ::= { + WITH SYNTAX HierarchyBelow + EQUALITY MATCHING RULE booleanMatch + SINGLE VALUE TRUE + NO USER MODIFICATION TRUE + USAGE directoryOperation + ID id-oa-hierarchyBelow +} + +HierarchyBelow ::= BOOLEAN + +hierarchyParent ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + USAGE directoryOperation + ID id-oa-hierarchyParent +} + +hierarchyTop ATTRIBUTE ::= { + WITH SYNTAX DistinguishedName + EQUALITY MATCHING RULE distinguishedNameMatch + SINGLE VALUE TRUE + USAGE directoryOperation + ID id-oa-hierarchyTop +} + +-- object identifier assignments +-- object classes +id-oc-top OBJECT IDENTIFIER ::= + {id-oc 0} + +id-oc-alias OBJECT IDENTIFIER ::= {id-oc 1} + +id-oc-parent OBJECT IDENTIFIER ::= {id-oc 28} + +id-oc-child OBJECT IDENTIFIER ::= {id-oc 29} + +-- attributes +id-at-objectClass OBJECT IDENTIFIER ::= {id-at 0} + +id-at-aliasedEntryName OBJECT IDENTIFIER ::= {id-at 1} + +-- matching rules +id-mr-objectIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 0} + +id-mr-distinguishedNameMatch OBJECT IDENTIFIER ::= {id-mr 1} + +-- operational attributes +id-oa-excludeAllCollectiveAttributes OBJECT IDENTIFIER ::= + {id-oa 0} + +id-oa-createTimestamp OBJECT IDENTIFIER ::= {id-oa 1} + +id-oa-modifyTimestamp OBJECT IDENTIFIER ::= {id-oa 2} + +id-oa-creatorsName OBJECT IDENTIFIER ::= {id-oa 3} + +id-oa-modifiersName OBJECT IDENTIFIER ::= {id-oa 4} + +id-oa-administrativeRole OBJECT IDENTIFIER ::= {id-oa 5} + +id-oa-subtreeSpecification OBJECT IDENTIFIER ::= {id-oa 6} + +id-oa-collectiveExclusions OBJECT IDENTIFIER ::= {id-oa 7} + +id-oa-subschemaTimestamp OBJECT IDENTIFIER ::= {id-oa 8} + +id-oa-hasSubordinates OBJECT IDENTIFIER ::= {id-oa 9} + +id-oa-subschemaSubentryList OBJECT IDENTIFIER ::= {id-oa 10} + +id-oa-accessControlSubentryList OBJECT IDENTIFIER ::= {id-oa 11} + +id-oa-collectiveAttributeSubentryList OBJECT IDENTIFIER ::= {id-oa 12} + +id-oa-contextDefaultSubentryList OBJECT IDENTIFIER ::= {id-oa 13} + +id-oa-contextAssertionDefault OBJECT IDENTIFIER ::= {id-oa 14} + +id-oa-serviceAdminSubentryList OBJECT IDENTIFIER ::= {id-oa 15} + +id-oa-searchRules OBJECT IDENTIFIER ::= {id-oa 16} + +id-oa-hierarchyLevel OBJECT IDENTIFIER ::= {id-oa 17} + +id-oa-hierarchyBelow OBJECT IDENTIFIER ::= {id-oa 18} + +id-oa-hierarchyParent OBJECT IDENTIFIER ::= {id-oa 19} + +id-oa-hierarchyTop OBJECT IDENTIFIER ::= {id-oa 20} + +-- subentry classes +id-sc-subentry OBJECT IDENTIFIER ::= {id-sc 0} + +id-sc-accessControlSubentry OBJECT IDENTIFIER ::= {id-sc 1} + +id-sc-collectiveAttributeSubentry OBJECT IDENTIFIER ::= {id-sc 2} + +id-sc-contextAssertionSubentry OBJECT IDENTIFIER ::= {id-sc 3} + +id-sc-serviceAdminSubentry OBJECT IDENTIFIER ::= {id-sc 4} + +-- Name forms +id-nf-subentryNameForm OBJECT IDENTIFIER ::= {id-nf 16} + +-- administrative roles +id-ar-autonomousArea OBJECT IDENTIFIER ::= {id-ar 1} + +id-ar-accessControlSpecificArea OBJECT IDENTIFIER ::= {id-ar 2} + +id-ar-accessControlInnerArea OBJECT IDENTIFIER ::= {id-ar 3} + +id-ar-subschemaAdminSpecificArea OBJECT IDENTIFIER ::= {id-ar 4} + +id-ar-collectiveAttributeSpecificArea OBJECT IDENTIFIER ::= {id-ar 5} + +id-ar-collectiveAttributeInnerArea OBJECT IDENTIFIER ::= {id-ar 6} + +id-ar-contextDefaultSpecificArea OBJECT IDENTIFIER ::= {id-ar 7} + +id-ar-serviceSpecificArea OBJECT IDENTIFIER ::= {id-ar 8} + +END -- InformationFramework diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile index c4f8d65aa7..2ce1168349 100644 --- a/lib/public_key/asn1/Makefile +++ b/lib/public_key/asn1/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2010. All Rights Reserved. +# Copyright Ericsson AB 2008-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -38,12 +38,12 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN) .SUFFIXES: .asn1 .PRECIOUS: %.erl -ASN_TOP = OTP-PUB-KEY +ASN_TOP = OTP-PUB-KEY PKCS-FRAME ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \ - PKIXAttributeCertificate PKCS-1 PKCS-3 OTP-PKIX + PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-8 InformationFramework PKCS5v2-0 OTP-PKIX ASN_ASNS = $(ASN_MODULES:%=%.asn1) -ASN_ERLS = $(ASN_TOP).erl -ASN_HRLS = $(ASN_TOP).hrl +ASN_ERLS = $(ASN_TOP:%=%.erl) +ASN_HRLS = $(ASN_TOP:%=%.hrl) ASN_CONFIGS = OTP-PUB-KEY.asn1config ASN_DBS = $(ASN_MODULES:%=%.asn1db) OTP-PUB-KEY.asn1db ASN_TABLES = $(ASN_MODULES:%=%.table) @@ -82,8 +82,8 @@ docs: %.erl %.hrl: %.set.asn erlc $(ASN_FLAGS) $< -$(HRL_FILES): $(ASN_HRLS) - cp -p $(ASN_HRLS) $(INCLUDE) +$(INCLUDE)/%.hrl: %.hrl + cp -p $< $@ # ---------------------------------------------------- # Release Target @@ -113,3 +113,9 @@ OTP-PUB-KEY.asn1db: PKIX1Algorithms88.asn1 \ PKCS-1.asn1\ PKCS-3.asn1\ OTP-PKIX.asn1 + +$(EBIN)/PKCS-FRAME.beam: PKCS-FRAME.erl PKCS-FRAME.hrl +PKCS-FRAME.erl PKCS-FRAME.hrl: PKCS-FRAME.asn1db +PKCS-FRAME.asn1db: PKCS-8.asn1\ + InformationFramework.asn1\ + PKCS5v2-0.asn1
\ No newline at end of file diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1 index b06f5efa9d..b06f5efa9d 100755..100644 --- a/lib/public_key/asn1/PKCS-1.asn1 +++ b/lib/public_key/asn1/PKCS-1.asn1 diff --git a/lib/public_key/asn1/PKCS-8.asn1 b/lib/public_key/asn1/PKCS-8.asn1 new file mode 100644 index 0000000000..7413519b57 --- /dev/null +++ b/lib/public_key/asn1/PKCS-8.asn1 @@ -0,0 +1,83 @@ +PKCS-8 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-8(8) + modules(1) pkcs-8(1)} + +-- $Revision: 1.5 $ + +-- This module has been checked for conformance with the ASN.1 +-- standard by the OSS ASN.1 Tools + +DEFINITIONS IMPLICIT TAGS ::= + +BEGIN + +-- EXPORTS All -- +-- All types and values defined in this module is exported for use in other +-- ASN.1 modules. + +IMPORTS + +-- informationFramework +-- FROM UsefulDefinitions {joint-iso-itu-t(2) ds(5) module(1) +-- usefulDefinitions(0) 3} + +Attribute +-- FROM InformationFramework informationFramework + FROM InformationFramework; + +-- This import is really unnecessary since ALGORITHM-IDENTIFIER is defined as a +-- TYPE-IDENTIFIER +-- Renome this import and replace all occurences of ALGORITHM-IDENTIFIER with +-- TYPE-IDENTIFIER as a workaround for weaknesses in the ASN.1 compiler +--AlgorithmIdentifier, ALGORITHM-IDENTIFIER +-- FROM PKCS5v2-0 {iso(1) member-body(2) us(840) rsadsi(113549) +-- pkcs(1) pkcs-5(5) modules(16) pkcs-5(1)}; + +-- Inlined from PKCS5v2-0 since it is the only thing imported from that module +-- AlgorithmIdentifier { ALGORITHM-IDENTIFIER:InfoObjectSet } ::= +AlgorithmIdentifier { TYPE-IDENTIFIER:InfoObjectSet } ::= +SEQUENCE { +-- algorithm ALGORITHM-IDENTIFIER.&id({InfoObjectSet}), + algorithm TYPE-IDENTIFIER.&id({InfoObjectSet}), +-- parameters ALGORITHM-IDENTIFIER.&Type({InfoObjectSet} + parameters TYPE-IDENTIFIER.&Type({InfoObjectSet} + {@algorithm}) OPTIONAL } + +-- Private-key information syntax + +PrivateKeyInfo ::= SEQUENCE { + version Version, +-- privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, + privateKeyAlgorithm AlgorithmIdentifier {{...}}, + privateKey PrivateKey, + attributes [0] Attributes OPTIONAL } + +Version ::= INTEGER {v1(0)} (v1,...) + +PrivateKey ::= OCTET STRING + +-- Attributes ::= SET OF Attribute +Attributes ::= SET OF Attribute {{...}} + +-- Encrypted private-key information syntax + +EncryptedPrivateKeyInfo ::= SEQUENCE { +-- encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + encryptionAlgorithm AlgorithmIdentifier {{...}}, + encryptedData EncryptedData +} + +EncryptedData ::= OCTET STRING + +-- PrivateKeyAlgorithms ALGORITHM-IDENTIFIER ::= { +PrivateKeyAlgorithms TYPE-IDENTIFIER ::= { + ... -- For local profiles +} + +-- KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= { +KeyEncryptionAlgorithms TYPE-IDENTIFIER ::= { + ... -- For local profiles +} + +END + + diff --git a/lib/public_key/asn1/PKCS-FRAME.set.asn b/lib/public_key/asn1/PKCS-FRAME.set.asn new file mode 100644 index 0000000000..a0777ff260 --- /dev/null +++ b/lib/public_key/asn1/PKCS-FRAME.set.asn @@ -0,0 +1,3 @@ +PKCS-8.asn1 +InformationFramework.asn1 +PKCS5v2-0.asn1 diff --git a/lib/public_key/asn1/PKCS5v2-0.asn1 b/lib/public_key/asn1/PKCS5v2-0.asn1 new file mode 100644 index 0000000000..fe7e16c7fa --- /dev/null +++ b/lib/public_key/asn1/PKCS5v2-0.asn1 @@ -0,0 +1,142 @@ +-- PKCS #5 v2.0 ASN.1 Module +-- Revised March 25, 1999 + +-- This module has been checked for conformance with the +-- ASN.1 standard by the OSS ASN.1 Tools + +PKCS5v2-0 {iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-5(5) modules(16) pkcs5v2-0(1)} + +DEFINITIONS ::= BEGIN + +-- Basic object identifiers + +rsadsi OBJECT IDENTIFIER ::= + {iso(1) member-body(2) us(840) 113549} +pkcs OBJECT IDENTIFIER ::= {rsadsi 1} +pkcs-5 OBJECT IDENTIFIER ::= {pkcs 5} + +-- Basic types and classes + +AlgorithmIdentifier { TYPE-IDENTIFIER:InfoObjectSet } ::= +SEQUENCE { + algorithm TYPE-IDENTIFIER.&id({InfoObjectSet}), + parameters TYPE-IDENTIFIER.&Type({InfoObjectSet} + {@algorithm}) OPTIONAL } + +--ALGORITHM-IDENTIFIER ::= TYPE-IDENTIFIER + +-- PBKDF2 + +-- PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= +-- { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} + +id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} + +-- algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= +-- {algorithm id-hmacWithSHA1, parameters NULL : NULL} + +PBKDF2-params ::= SEQUENCE { + salt CHOICE { + specified OCTET STRING, + otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + }, + iterationCount INTEGER (1..MAX), + keyLength INTEGER (1..MAX) OPTIONAL, + prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT +{algorithm id-hmacWithSHA1, parameters NULL : NULL}} +-- algid-hmacWithSHA1 } + +PBKDF2-SaltSources TYPE-IDENTIFIER ::= { ... } + +PBKDF2-PRFs TYPE-IDENTIFIER ::= + { {NULL IDENTIFIED BY id-hmacWithSHA1}, ... } + + -- PBES1 + +PBES1Algorithms TYPE-IDENTIFIER ::= + { {PBEParameter IDENTIFIED BY pbeWithMD2AndDES-CBC} | + {PBEParameter IDENTIFIED BY pbeWithMD2AndRC2-CBC} | + {PBEParameter IDENTIFIED BY pbeWithMD5AndDES-CBC} | + {PBEParameter IDENTIFIED BY pbeWithMD5AndRC2-CBC} | + {PBEParameter IDENTIFIED BY pbeWithSHA1AndDES-CBC} | + {PBEParameter IDENTIFIED BY pbeWithSHA1AndRC2-CBC}, ...} + +pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} +pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} +pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} +pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} +pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} +pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} + +PBEParameter ::= SEQUENCE { + salt OCTET STRING (SIZE(8)), + iterationCount INTEGER } + +-- PBES2 + +PBES2Algorithms TYPE-IDENTIFIER ::= + { {PBES2-params IDENTIFIED BY id-PBES2}, ...} + +id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} + +PBES2-params ::= SEQUENCE { + keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } + +PBES2-KDFs TYPE-IDENTIFIER ::= + { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } + +PBES2-Encs TYPE-IDENTIFIER ::= { ... } + +-- PBMAC1 + +PBMAC1Algorithms TYPE-IDENTIFIER ::= + { {PBMAC1-params IDENTIFIED BY id-PBMAC1}, ...} + +id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} + +PBMAC1-params ::= SEQUENCE { + keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}}, + messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} } + +PBMAC1-KDFs TYPE-IDENTIFIER ::= + { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } + +PBMAC1-MACs TYPE-IDENTIFIER ::= { ... } + +-- Supporting techniques + +digestAlgorithm OBJECT IDENTIFIER ::= {rsadsi 2} +encryptionAlgorithm OBJECT IDENTIFIER ::= {rsadsi 3} + +SupportingAlgorithms TYPE-IDENTIFIER ::= + { {NULL IDENTIFIED BY id-hmacWithSHA1} | + {OCTET STRING (SIZE(8)) IDENTIFIED BY desCBC} | + {OCTET STRING (SIZE(8)) IDENTIFIED BY des-EDE3-CBC} | + {RC2-CBC-Parameter IDENTIFIED BY rc2CBC} | + {RC5-CBC-Parameters IDENTIFIED BY rc5-CBC-PAD}, ... } + +id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} + +desCBC OBJECT IDENTIFIER ::= + {iso(1) identified-organization(3) oiw(14) secsig(3) + algorithms(2) 7} -- from OIW + +des-EDE3-CBC OBJECT IDENTIFIER ::= {encryptionAlgorithm 7} + +rc2CBC OBJECT IDENTIFIER ::= {encryptionAlgorithm 2} + +RC2-CBC-Parameter ::= SEQUENCE { + rc2ParameterVersion INTEGER OPTIONAL, + iv OCTET STRING (SIZE(8)) } + +rc5-CBC-PAD OBJECT IDENTIFIER ::= {encryptionAlgorithm 9} + +RC5-CBC-Parameters ::= SEQUENCE { + version INTEGER {v1-0(16)}, -- (v1-0), + rounds INTEGER (8..127), + blockSizeInBits INTEGER (64 | 128), + iv OCTET STRING OPTIONAL } + +END diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile index afb17399da..9616a96195 100644 --- a/lib/public_key/doc/src/Makefile +++ b/lib/public_key/doc/src/Makefile @@ -29,14 +29,6 @@ VSN=$(PUBLIC_KEY_VSN) APPLICATION=public_key # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -79,33 +71,10 @@ EXTRA_FILES = \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_PART_FILES:%.xml=%.tex) \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = public_key-$(VSN).pdf -TOP_PS_FILE = public_key-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -118,8 +87,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -134,33 +101,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ min_head.gif \ - $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -173,8 +113,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -184,30 +122,6 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif - release_spec: info: diff --git a/lib/public_key/doc/src/make.dep b/lib/public_key/doc/src/make.dep deleted file mode 100644 index 2675556f1b..0000000000 --- a/lib/public_key/doc/src/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex cert_records.tex introduction.tex \ - part.tex public_key.tex public_key_records.tex \ - ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 9a3832c68b..821e7a2300 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -61,11 +61,14 @@ <p><code>string = [bytes()]</code></p> <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' - 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</code></p> + 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'| 'PrivateKeyInfo'</code></p> <p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER - not_encrypted | {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</code></p> - + not_encrypted | cipher_info()} </code></p> + + <p><code>cipher_info() = {"RC2-CBC | "DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)} | + 'PBES2-params'} </code></p> + <p><code>rsa_public_key() = #'RSAPublicKey'{}</code></p> <p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p> @@ -118,7 +121,8 @@ <funcs> <func> - <name>decrypt_private(CipherText, Key [, Options]) -> binary()</name> + <name>decrypt_private(CipherText, Key) -> binary()</name> + <name>decrypt_private(CipherText, Key, Options) -> binary()</name> <fsummary>Public key decryption.</fsummary> <type> <v>CipherText = binary()</v> @@ -131,7 +135,8 @@ </func> <func> - <name>decrypt_public(CipherText, Key [, Options]) - > binary()</name> + <name>decrypt_public(CipherText, Key) - > binary()</name> + <name>decrypt_public(CipherText, Key, Options) - > binary()</name> <fsummary></fsummary> <type> <v>CipherText = binary()</v> @@ -198,7 +203,8 @@ </func> <func> - <name>pem_entry_decode(PemEntry [, Password]) -> term()</name> + <name>pem_entry_decode(PemEntry) -> term()</name> + <name>pem_entry_decode(PemEntry, Password) -> term()</name> <fsummary>Decodes a pem entry.</fsummary> <type> <v> PemEntry = pem_entry() </v> @@ -213,7 +219,8 @@ </func> <func> - <name>pem_entry_encode(Asn1Type, Entity [,{CipherInfo, Password}]) -> pem_entry()</name> + <name>pem_entry_encode(Asn1Type, Entity) -> pem_entry()</name> + <name>pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry()</name> <fsummary> Creates a pem entry that can be fed to pem_encode/1.</fsummary> <type> <v>Asn1Type = pki_asn1_type()</v> @@ -224,7 +231,7 @@ dsa_public_key() and this function will create the appropriate 'SubjectPublicKeyInfo' entry. </d> - <v>CipherInfo = {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}</v> + <v>CipherInfo = cipher_info()</v> <v>Password = string()</v> </type> <desc> diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 5f97d80f7e..2475295974 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -23,6 +23,7 @@ -define(public_key, true). -include("OTP-PUB-KEY.hrl"). +-include("PKCS-FRAME.hrl"). -record('SubjectPublicKeyInfoAlgorithm', { algorithm, diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile index 5a24b02d2a..062c495a65 100644 --- a/lib/public_key/src/Makefile +++ b/lib/public_key/src/Makefile @@ -42,10 +42,11 @@ MODULES = \ public_key \ pubkey_pem \ pubkey_ssh \ + pubkey_pbe \ pubkey_cert \ - pubkey_cert_records + pubkey_cert_records -HRL_FILES = $(INCLUDE)/public_key.hrl +HRL_FILES = $(INCLUDE)/public_key.hrl INTERNAL_HRL_FILES = @@ -109,4 +110,3 @@ release_spec: opt $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin release_docs_spec: - diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl new file mode 100644 index 0000000000..43f6c42f10 --- /dev/null +++ b/lib/public_key/src/pubkey_pbe.erl @@ -0,0 +1,213 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% Description: Implements Password Based Encryption PKCS-5, RFC-2898 + +-module(pubkey_pbe). + +-include("public_key.hrl"). + +-export([encode/4, decode/4, decrypt_parameters/1]). +-export([pbdkdf1/4, pbdkdf2/6]). + +-define(DEFAULT_SHA_MAC_KEYLEN, 20). +-define(ASN1_OCTET_STR_TAG, 4). +-define(IV_LEN, 8). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +%%-------------------------------------------------------------------- +-spec encode(binary(), string(), string(), term()) -> binary(). +%% +%% Description: Performs password based encoding +%%-------------------------------------------------------------------- +encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + crypto:des_cbc_encrypt(Key, IV, Data); + +encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, + crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data); + +encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + crypto:rc2_cbc_encrypt(Key, IV, Data). +%%-------------------------------------------------------------------- +-spec decode(binary(), string(), string(), term()) -> binary(). +%% +%% Description: Performs password based decoding +%%-------------------------------------------------------------------- +decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + crypto:des_cbc_decrypt(Key, IV, Data); + +decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, + crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data); + +decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) -> + {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), + crypto:rc2_cbc_decrypt(Key, IV, Data). + +%%-------------------------------------------------------------------- +-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary(). +%% +%% Description: Implements password based decryption key derive function 1. +%% Exported mainly for testing purposes. +%%-------------------------------------------------------------------- +pbdkdf1(_, _, 0, Acc) -> + Acc; +pbdkdf1(Password, Salt, Count, Hash) -> + Result = crypto:Hash([Password, Salt]), + do_pbdkdf1(Result, Count-1, Result, Hash). + +%%-------------------------------------------------------------------- +-spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), integer()) + -> binary(). +%% +%% Description: Implements password based decryption key derive function 2. +%% Exported mainly for testing purposes. +%%-------------------------------------------------------------------- +pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfOutputLen)-> + NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen), + NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen , + blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt, + Count, Prf, PrfOutputLen, <<>>). +%%-------------------------------------------------------------------- +-spec decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}) -> + {Cipher::string(), #'PBES2-params'{}}. +%% +%% Description: Performs ANS1-decoding of encryption parameters. +%%-------------------------------------------------------------------- +decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{ + algorithm = Oid, parameters = Param}) -> + decrypt_parameters(Oid, Param). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) -> + {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen, IV} = + key_derivation_params(Params), + <<Key:KeyLen/binary, _/binary>> = + pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen), + {Key, IV}; +password_to_key_and_iv(Password, Cipher, Salt) -> + KeyLen = derived_key_length(Cipher, undefined), + <<Key:KeyLen/binary, _/binary>> = + pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5), + %% Old PEM encryption does not use standard encryption method + %% pbdkdf1 and uses then salt as IV + {Key, Salt}. + +pem_encrypt(_, _, _, 0, Acc, _) -> + Acc; +pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) -> + Result = crypto:Hash([Prev, Password, Salt]), + pem_encrypt(Result, Password, Salt, Count-1 , <<Acc/binary, Result/binary>>, Hash). + +do_pbdkdf1(_, 0, Acc, _) -> + Acc; +do_pbdkdf1(Prev, Count, Acc, Hash) -> + Result = crypto:Hash(Prev), + do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash). + +iv(#'PBES2-params_encryptionScheme'{algorithm = Algo, + parameters = ASNIV}) when (Algo == ?'desCBC') or + (Algo == ?'des-EDE3-CBC') -> + %% This is an so called open ASN1-type that in this + %% case will be an octet-string of length 8 + <<?ASN1_OCTET_STR_TAG, ?IV_LEN, IV:?IV_LEN/binary>> = ASNIV, + IV; +iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC', + parameters = ASN1IV}) -> + {ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', ASN1IV), + iolist_to_binary(IV). + +blocks(1, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) -> + <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfLen), + <<Acc/binary, XorSum/binary>>; +blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) -> + XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfLen), + blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf, + PrfLen, <<Acc/binary, XorSum/binary>>). + +xor_sum(Password, Salt, Count, Index, Prf, PrfLen) -> + Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen), + do_xor_sum(Prf, PrfLen, Result, Password, Count-1, Result). + +do_xor_sum(_, _, _, _, 0, Acc) -> + Acc; +do_xor_sum(Prf, PrfLen, Prev, Password, Count, Acc)-> + Result = Prf(Password, Prev, PrfLen), + do_xor_sum(Prf, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)). + +decrypt_parameters(?'id-PBES2', DekParams) -> + {ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams), + {cipher(Params#'PBES2-params'.encryptionScheme), Params}. + +key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc, + encryptionScheme = EncScheme}) -> + #'PBES2-params_keyDerivationFunc'{algorithm = ?'id-PBKDF2', + parameters = + #'PBKDF2-params'{salt = {specified, OctetSalt}, + iterationCount = Count, + keyLength = Length, + prf = Prf}} = KeyDerivationFunc, + #'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme, + {PseudoRandomFunction, PseudoOtputLen} = pseudo_random_function(Prf), + KeyLen = derived_key_length(Algo, Length), + {OctetSalt, Count, KeyLen, + PseudoRandomFunction, PseudoOtputLen, iv(EncScheme)}. + +%% This function currently matches a tuple that ougth to be the value +%% ?'id-hmacWithSHA1, but we need some kind of ASN1-fix for this. +pseudo_random_function(#'PBKDF2-params_prf'{algorithm = + {_,_, _,'id-hmacWithSHA1'}}) -> + {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}; +pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) -> + {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}. + +pseudo_output_length(?'id-hmacWithSHA1') -> + ?DEFAULT_SHA_MAC_KEYLEN. + +derived_key_length(_, Len) when is_integer(Len) -> + Len; +derived_key_length(Cipher,_) when (Cipher == ?'desCBC') or + (Cipher == "DES-CBC") -> + 8; +derived_key_length(Cipher,_) when (Cipher == ?'rc2CBC') or + (Cipher == "RC2-CBC") -> + 16; +derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or + (Cipher == "DES-EDE3-CBC") -> + 24. + +cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) -> + "DES-CBC"; +cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'des-EDE3-CBC'}) -> + "DES-EDE3-CBC"; +cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC'}) -> + "RC2-CBC". + +ceiling(Float) -> + erlang:round(Float + 0.5). diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index c26815bc04..910473d629 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -43,8 +43,6 @@ -include("public_key.hrl"). -export([encode/1, decode/1, decipher/2, cipher/3]). -%% Backwards compatibility --export([decode_key/2]). -define(ENCODED_LINE_LENGTH, 64). @@ -69,23 +67,23 @@ encode(PemEntries) -> encode_pem_entries(PemEntries). %%-------------------------------------------------------------------- --spec decipher({pki_asn1_type(), DerEncrypted::binary(),{Cipher :: string(), - Salt :: binary()}}, +-spec decipher({pki_asn1_type(), DerEncrypted::binary(), + {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{}}}, string()) -> Der::binary(). %% %% Description: Deciphers a decrypted pem entry. %%-------------------------------------------------------------------- -decipher({_, DecryptDer, {Cipher,Salt}}, Password) -> - decode_key(DecryptDer, Password, Cipher, Salt). +decipher({_, DecryptDer, {Cipher, KeyDevParams}}, Password) -> + pubkey_pbe:decode(DecryptDer, Password, Cipher, KeyDevParams). %%-------------------------------------------------------------------- --spec cipher(Der::binary(),{Cipher :: string(), Salt :: binary()} , +-spec cipher(Der::binary(), {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{}} , string()) -> binary(). %% %% Description: Ciphers a PEM entry %%-------------------------------------------------------------------- -cipher(Der, {Cipher,Salt}, Password)-> - encode_key(Der, Password, Cipher, Salt). +cipher(Der, {Cipher, KeyDevParams}, Password)-> + pubkey_pbe:encode(Der, Password, Cipher, KeyDevParams). %%-------------------------------------------------------------------- %%% Internal functions @@ -127,8 +125,20 @@ decode_pem_entry(Start, Lines) -> Type = asn1_type(Start), Cs = erlang:iolist_to_binary(Lines), Decoded = base64:mime_decode(Cs), - {Type, Decoded, not_encrypted}. - + case Type of + 'EncryptedPrivateKeyInfo'-> + decode_encrypted_private_keyinfo(Decoded); + _ -> + {Type, Decoded, not_encrypted} + end. + +decode_encrypted_private_keyinfo(Der) -> + #'EncryptedPrivateKeyInfo'{encryptionAlgorithm = AlgorithmInfo, + encryptedData = Data} = + public_key:der_decode('EncryptedPrivateKeyInfo', Der), + DecryptParams = pubkey_pbe:decrypt_parameters(AlgorithmInfo), + {'PrivateKeyInfo', iolist_to_binary(Data), DecryptParams}. + split_bin(Bin) -> split_bin(0, Bin). @@ -160,37 +170,6 @@ join_entry([<<"-----END ", _/binary>>| Lines], Entry) -> join_entry([Line | Lines], Entry) -> join_entry(Lines, [Line | Entry]). -decode_key(Data, Password, "DES-CBC", Salt) -> - Key = password_to_key(Password, Salt, 8), - IV = Salt, - crypto:des_cbc_decrypt(Key, IV, Data); -decode_key(Data, Password, "DES-EDE3-CBC", Salt) -> - Key = password_to_key(Password, Salt, 24), - IV = Salt, - <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, - crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data). - -encode_key(Data, Password, "DES-CBC", Salt) -> - Key = password_to_key(Password, Salt, 8), - IV = Salt, - crypto:des_cbc_encrypt(Key, IV, Data); -encode_key(Data, Password, "DES-EDE3-CBC", Salt) -> - Key = password_to_key(Password, Salt, 24), - IV = Salt, - <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, - crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data). - -password_to_key(Data, Salt, KeyLen) -> - <<Key:KeyLen/binary, _/binary>> = - password_to_key(<<>>, Data, Salt, KeyLen, <<>>), - Key. - -password_to_key(_, _, _, Len, Acc) when Len =< 0 -> - Acc; -password_to_key(Prev, Data, Salt, Len, Acc) -> - M = crypto:md5([Prev, Data, Salt]), - password_to_key(M, Data, Salt, Len - size(M), <<Acc/binary, M/binary>>). - unhex(S) -> unhex(S, []). @@ -228,6 +207,10 @@ pem_end(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> <<"-----END DSA PRIVATE KEY-----">>; pem_end(<<"-----BEGIN DH PARAMETERS-----">>) -> <<"-----END DH PARAMETERS-----">>; +pem_end(<<"-----BEGIN PRIVATE KEY-----">>) -> + <<"-----END PRIVATE KEY-----">>; +pem_end(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) -> + <<"-----END ENCRYPTED PRIVATE KEY-----">>; pem_end(_) -> undefined. @@ -242,18 +225,14 @@ asn1_type(<<"-----BEGIN PUBLIC KEY-----">>) -> asn1_type(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> 'DSAPrivateKey'; asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) -> - 'DHParameter'. + 'DHParameter'; +asn1_type(<<"-----BEGIN PRIVATE KEY-----">>) -> + 'PrivateKeyInfo'; +asn1_type(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) -> + 'EncryptedPrivateKeyInfo'. pem_decrypt() -> <<"Proc-Type: 4,ENCRYPTED">>. pem_decrypt_info(Cipher, Salt) -> io_lib:format("DEK-Info: ~s,~s", [Cipher, lists:flatten(hexify(Salt))]). - -%%-------------------------------------------------------------------- -%%% Deprecated -%%-------------------------------------------------------------------- -decode_key({_Type, Bin, not_encrypted}, _) -> - Bin; -decode_key({_Type, Bin, {Chipher,Salt}}, Password) -> - decode_key(Bin, Password, Chipher, Salt). diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src index 1963bd05d4..4cc81ea573 100644 --- a/lib/public_key/src/public_key.app.src +++ b/lib/public_key/src/public_key.app.src @@ -3,10 +3,12 @@ {vsn, "%VSN%"}, {modules, [ public_key, pubkey_pem, + pubkey_pbe, pubkey_ssh, pubkey_cert, pubkey_cert_records, - 'OTP-PUB-KEY' + 'OTP-PUB-KEY', + 'PKCS-FRAME' ]}, {applications, [crypto, kernel, stdlib]}, {registered, []}, diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 4986801dad..2945fb1213 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,70 +1,16 @@ %% -*- erlang -*- {"%VSN%", [ - {"0.11", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {add_module, pubkey_ssh, soft, soft_purge, soft_purge}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} - ] - }, - - {"0.10", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} - ] - }, - {"0.9", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] - }, - {"0.8", - [ - {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] - } + {"0.13", [{restart_application, public_key}]}, + {"0.11", [{restart_application, public_key}]}, + {"0.10", [{restart_application, public_key}]}, + {"0.9", [{restart_application, public_key}]}, + {"0.8", [{restart_application, public_key}]} ], [ - {"0.11", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {delete_module, pubkey_ssh, soft, soft_purge, soft_purge}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} - ] - }, - - {"0.10", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} - ] - }, - {"0.9", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] - }, - {"0.8", - [ - {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_pem, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] - } + {"0.13", [{restart_application, public_key}]}, + {"0.11", [{restart_application, public_key}]}, + {"0.10", [{restart_application, public_key}]}, + {"0.9", [{restart_application, public_key}]}, + {"0.8", [{restart_application, public_key}]} ]}. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 33fcce2c44..753322b46d 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -45,13 +45,6 @@ ssh_decode/2, ssh_encode/2 ]). -%% Deprecated --export([decode_private_key/1, decode_private_key/2, pem_to_der/1]). - --deprecated({pem_to_der, 1, next_major_release}). --deprecated({decode_private_key, 1, next_major_release}). --deprecated({decode_private_key, 2, next_major_release}). - -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. @@ -104,22 +97,23 @@ pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type), pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type), is_binary(Der) -> der_decode(Asn1Type, Der); +pem_entry_decode({Asn1Type, CryptDer, {Cipher, #'PBES2-params'{}}} = PemEntry, + Password) when is_atom(Asn1Type) andalso + is_binary(CryptDer) andalso + is_list(Cipher) -> + do_pem_entry_decode(PemEntry, Password); pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry, - Password) when is_atom(Asn1Type), - is_binary(CryptDer), - is_list(Cipher), - is_binary(Salt), - erlang:byte_size(Salt) == 8 - -> - Der = pubkey_pem:decipher(PemEntry, Password), - der_decode(Asn1Type, Der). + Password) when is_atom(Asn1Type) andalso + is_binary(CryptDer) andalso + is_list(Cipher) andalso + is_binary(Salt) andalso + erlang:byte_size(Salt) == 8 -> + do_pem_entry_decode(PemEntry, Password). %%-------------------------------------------------------------------- -spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry(). --spec pem_entry_encode(pki_asn1_type(), term(), - {{Cipher :: string(), Salt :: binary()}, string()}) -> - pem_entry(). -% +-spec pem_entry_encode(pki_asn1_type(), term(), term()) -> pem_entry(). +%% %% Description: Creates a pem entry that can be feed to pem_encode/1. %%-------------------------------------------------------------------- pem_entry_encode('SubjectPublicKeyInfo', Entity=#'RSAPublicKey'{}) -> @@ -137,21 +131,36 @@ pem_entry_encode('SubjectPublicKeyInfo', pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> Der = der_encode(Asn1Type, Entity), {Asn1Type, Der, not_encrypted}. -pem_entry_encode(Asn1Type, Entity, - {{Cipher, Salt}= CipherInfo, Password}) when is_atom(Asn1Type), - is_list(Cipher), - is_binary(Salt), - erlang:byte_size(Salt) == 8, - is_list(Password)-> - Der = der_encode(Asn1Type, Entity), - DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password), - {Asn1Type, DecryptDer, CipherInfo}. - +pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo, + Password}) when is_atom(Asn1Type) andalso + is_list(Password) andalso + is_list(Cipher) -> + do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password); + +pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo, + Password}) when is_atom(Asn1Type) andalso + is_list(Password) andalso + is_list(Cipher) andalso + is_binary(Salt) andalso + erlang:byte_size(Salt) == 8 -> + do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password). + %%-------------------------------------------------------------------- -spec der_decode(asn1_type(), Der::binary()) -> term(). %% %% Description: Decodes a public key asn1 der encoded entity. %%-------------------------------------------------------------------- +der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or + (Asn1Type == 'EncryptedPrivateKeyInfo') + andalso is_binary(Der) -> + try + {ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der), + Decoded + catch + error:{badmatch, {error, _}} = Error -> + erlang:error(Error) + end; + der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) -> try {ok, Decoded} = 'OTP-PUB-KEY':decode(Asn1Type, Der), @@ -166,6 +175,16 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) -> %% %% Description: Encodes a public key entity with asn1 DER encoding. %%-------------------------------------------------------------------- +der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or + (Asn1Type == 'EncryptedPrivateKeyInfo') -> + try + {ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity), + iolist_to_binary(Encoded) + catch + error:{badmatch, {error, _}} = Error -> + erlang:error(Error) + end; + der_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> try {ok, Encoded} = 'OTP-PUB-KEY':encode(Asn1Type, Entity), @@ -535,6 +554,14 @@ ssh_encode(Entries, Type) when is_list(Entries), %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password) -> + Der = der_encode(Asn1Type, Entity), + DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password), + {Asn1Type, DecryptDer, CipherInfo}. + +do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) -> + Der = pubkey_pem:decipher(PemEntry, Password), + der_decode(Asn1Type, Der). encrypt_public(PlainText, N, E, Options)-> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), @@ -632,20 +659,3 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer, sized_binary(Binary) -> Size = size(Binary), <<?UINT32(Size), Binary/binary>>. - -%%-------------------------------------------------------------------- -%%% Deprecated functions -%%-------------------------------------------------------------------- -pem_to_der(CertSource) -> - {ok, Bin} = file:read_file(CertSource), - {ok, pubkey_pem:decode(Bin)}. - -decode_private_key(KeyInfo) -> - decode_private_key(KeyInfo, no_passwd). - -decode_private_key(KeyInfo = {'RSAPrivateKey', _, _}, Password) -> - DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), - 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded); -decode_private_key(KeyInfo = {'DSAPrivateKey', _, _}, Password) -> - DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), - 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded). diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile index 6889ae9a8a..b7f91981a5 100644 --- a/lib/public_key/test/Makefile +++ b/lib/public_key/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2010. All Rights Reserved. +# Copyright Ericsson AB 2008-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -30,6 +30,7 @@ INCLUDES= -I. -I ../include MODULES= \ erl_make_certs \ public_key_SUITE \ + pbe_SUITE \ pkits_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl new file mode 100644 index 0000000000..380a67db7b --- /dev/null +++ b/lib/public_key/test/pbe_SUITE.erl @@ -0,0 +1,259 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(pbe_SUITE). + +-include_lib("test_server/include/test_server.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + try crypto:start() of + ok -> + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + application:stop(crypto). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + pbdkdf1, + pbdkdf2, + encrypted_private_key_info]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%% Test cases starts here. +%%-------------------------------------------------------------------- +pbdkdf1(doc) -> + ["Test with PKCS #5 PBKDF1 Test Vectors"]; +pbdkdf1(Config) when is_list(Config) -> + %%Password = "password" + %% = (0x)70617373776F7264 + %%Salt = (0x)78578E5A5D63CB06 + %%Count = 1000 + %%kLen = 16 + %%Key = PBKDF1(Password, Salt, Count, kLen) + %%= (0x)DC19847E05C64D2FAF10EBFB4A3D2A20 + + Password = "password", + Salt = <<16#78,16#57,16#8E,16#5A,16#5D,16#63,16#CB,16#06>>, + Count = 1000, + + <<16#DC, 16#19, 16#84, 16#7E, + 16#05, 16#C6, 16#4D, 16#2F, + 16#AF, 16#10, 16#EB, 16#FB, + 16#4A, 16#3D, 16#2A, 16#20, _/binary>> = + pubkey_pbe:pbdkdf1(Password, Salt, Count, sha). + +pbdkdf2(doc) -> + ["Test with PKCS #5 PBKDF2 Test Vectors"]; +pbdkdf2(Config) when is_list(Config) -> + %% Input: + %% P = "password" (8 octets) + %% S = "salt" (4 octets) + %% c = 1 + %% dkLen = 20 + + %% Output: + %% DK = 0c 60 c8 0f 96 1f 0e 71 + %% f3 a9 b5 24 af 60 12 06 + %% 2f e0 37 a6 (20 octets) + + <<16#0c, 16#60, 16#c8, 16#0f, 16#96, 16#1f, 16#0e, 16#71, + 16#f3, 16#a9, 16#b5, 16#24, 16#af, 16#60, 16#12, 16#06, + 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:sha_mac/3, 20), + + %% Input: + %% P = "password" (8 octets) + %% S = "salt" (4 octets) + %% c = 2 + %% dkLen = 20 + + %% Output: + %% DK = ea 6c 01 4d c7 2d 6f 8c + %% cd 1e d9 2a ce 1d 41 f0 + %% d8 de 89 57 (20 octets) + + <<16#ea, 16#6c, 16#01, 16#4d, 16#c7, 16#2d, 16#6f, 16#8c, + 16#cd, 16#1e, 16#d9, 16#2a, 16#ce, 16#1d, 16#41, 16#f0, + 16#d8, 16#de, 16#89, 16#57>> = + pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:sha_mac/3, 20), + + %% Input: + %% P = "password" (8 octets) + %% S = "salt" (4 octets) + %% c = 4096 + %% dkLen = 20 + + %% Output: + %% DK = 4b 00 79 01 b7 65 48 9a + %% be ad 49 d9 26 f7 21 d0 + %% 65 a4 29 c1 (20 octets) + + <<16#4b, 16#00, 16#79, 16#01, 16#b7, 16#65, 16#48, 16#9a, + 16#be, 16#ad, 16#49, 16#d9, 16#26, 16#f7, 16#21, 16#d0, + 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:sha_mac/3, 20), + + %% Input: + %% P = "password" (8 octets) + %% S = "salt" (4 octets) + %% c = 16777216 + %% dkLen = 20 + + %% Output: + %% DK = ee fe 3d 61 cd 4d a4 e4 + %% e9 94 5b 3d 6b a2 15 8c + %% 26 34 e9 84 (20 octets) + + + <<16#ee, 16#fe, 16#3d, 16#61, 16#cd, 16#4d, 16#a4, 16#e4, + 16#e9, 16#94, 16#5b, 16#3d, 16#6b, 16#a2, 16#15, 16#8c, + 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:sha_mac/3, 20), + + %% Input: + %% P = "passwordPASSWORDpassword" (24 octets) + %% S = "saltSALTsaltSALTsaltSALTsaltSALTsalt" (36 octets) + %% c = 4096 + %% dkLen = 25 + + %% Output: + %% DK = 3d 2e ec 4f e4 1c 84 9b + %% 80 c8 d8 36 62 c0 e4 4a + %% 8b 29 1a 96 4c f2 f0 70 + %% 38 (25 octets) + + <<16#3d, 16#2e, 16#ec, 16#4f, 16#e4, 16#1c, 16#84, 16#9b, + 16#80, 16#c8, 16#d8, 16#36, 16#62, 16#c0, 16#e4, 16#4a, + 16#8b, 16#29, 16#1a, 16#96, 16#4c, 16#f2, 16#f0, 16#70, + 16#38>> + = pubkey_pbe:pbdkdf2("passwordPASSWORDpassword", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:sha_mac/3, 20), + + %% Input: + %% P = "pass\0word" (9 octets) + %% S = "sa\0lt" (5 octets) + %% c = 4096 + %% dkLen = 16 + + %% Output: + %% DK = 56 fa 6a a7 55 48 09 9d + %% cc 37 d7 f0 34 25 e0 c3 (16 octets) + + <<16#56, 16#fa, 16#6a, 16#a7, 16#55, 16#48, 16#09, 16#9d, + 16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>> + = pubkey_pbe:pbdkdf2("pass\0word", + "sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20). + +encrypted_private_key_info(doc) -> + ["Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"]; +encrypted_private_key_info(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + {ok, PemDes} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")), + + PemDesEntry = public_key:pem_decode(PemDes), + test_server:format("Pem entry: ~p" , [PemDesEntry]), + [{'PrivateKeyInfo', _, {"DES-CBC",_}} = PubEntry0] = PemDesEntry, + KeyInfo = public_key:pem_entry_decode(PubEntry0, "password"), + + {ok, Pem3Des} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")), + + Pem3DesEntry = public_key:pem_decode(Pem3Des), + test_server:format("Pem entry: ~p" , [Pem3DesEntry]), + [{'PrivateKeyInfo', _, {"DES-EDE3-CBC",_}} = PubEntry1] = Pem3DesEntry, + KeyInfo = public_key:pem_entry_decode(PubEntry1, "password"), + + {ok, PemRc2} = file:read_file(filename:join(Datadir, "rc2_cbc_enc_key.pem")), + + PemRc2Entry = public_key:pem_decode(PemRc2), + test_server:format("Pem entry: ~p" , [PemRc2Entry]), + [{'PrivateKeyInfo', _, {"RC2-CBC",_}} = PubEntry2] = PemRc2Entry, + KeyInfo = public_key:pem_entry_decode(PubEntry2, "password"), + + check_key_info(KeyInfo). + + +check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm = + #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption}, + privateKey = Key}) -> + #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)). diff --git a/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem new file mode 100644 index 0000000000..eaa06145aa --- /dev/null +++ b/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA +MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y +9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ +0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo +f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO +Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v +aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks +2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM +75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA +-----END ENCRYPTED PRIVATE KEY----- diff --git a/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem new file mode 100644 index 0000000000..22ea46d56f --- /dev/null +++ b/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA +MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/ +koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8 ++MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5 +6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi +5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ +BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8 +z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr +u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB +-----END ENCRYPTED PRIVATE KEY----- diff --git a/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem new file mode 100644 index 0000000000..618cddcfd7 --- /dev/null +++ b/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem @@ -0,0 +1,12 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA +AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop +7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f +wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21 +RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6 +VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1 +MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz +tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH +2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO +6DA= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index b11e4d092a..a91dcfa029 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -23,8 +23,8 @@ %% Note: This directive should only be used in test suites. -compile(export_all). --include_lib("common_test/include/ct.hrl"). --include_lib("test_server/include/test_server_line.hrl"). +%%-include_lib("common_test/include/ct.hrl"). +-include_lib("test_server/include/test_server.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -107,7 +107,7 @@ all() -> {group, ssh_public_key_decode_encode}, encrypt_decrypt, {group, sign_verify}, - pkix, pkix_path_validation, deprecated]. + pkix, pkix_path_validation]. groups() -> [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem, @@ -699,27 +699,6 @@ pkix_path_validation(Config) when is_list(Config) -> VerifyFunAndState1}]), ok. -%%-------------------------------------------------------------------- -deprecated(doc) -> - ["Check deprecated functions."]; -deprecated(suite) -> - []; -deprecated(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), - {ok, [DsaKey = {'DSAPrivateKey', _DsaKey, _}]} = - public_key:pem_to_der(filename:join(Datadir, "dsa.pem")), - {ok, [RsaKey = {'RSAPrivateKey', _RsaKey,_}]} = - public_key:pem_to_der(filename:join(Datadir, "client_key.pem")), - {ok, [ProtectedRsaKey = {'RSAPrivateKey', _ProtectedRsaKey,_}]} = - public_key:pem_to_der(filename:join(Datadir, "rsa.pem")), - - {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey), - {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey), - {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey, "abcd1234"), - ok. - -%%-------------------------------------------------------------------- - check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') -> true; check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') -> diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 66ac78a65d..d8f811bf25 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.13 +PUBLIC_KEY_VSN = 0.14 diff --git a/lib/reltool/doc/src/make.dep b/lib/reltool/doc/src/make.dep deleted file mode 100644 index 59e77e8162..0000000000 --- a/lib/reltool/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex reltool.tex \ - reltool_examples.tex reltool_intro.tex reltool_usage.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/runtime_tools/doc/src/make.dep b/lib/runtime_tools/doc/src/make.dep deleted file mode 100644 index 85eae88adf..0000000000 --- a/lib/runtime_tools/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex dbg.tex erts_alloc_config.tex refman.tex \ - runtime_tools_app.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: refman.xml - diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl index 0bcb202fd8..1a57c94443 100644 --- a/lib/runtime_tools/src/erts_alloc_config.erl +++ b/lib/runtime_tools/src/erts_alloc_config.erl @@ -1,6 +1,7 @@ +%% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -16,6 +17,7 @@ %% The Initial Developer of the Original Code is Ericsson AB. %% %% %CopyrightEnd% +%% %%%------------------------------------------------------------------- %%% File : erts_alloc_config.erl @@ -71,6 +73,7 @@ A == binary_alloc; A == std_alloc; A == ets_alloc; + A == fix_alloc; A == eheap_alloc; A == ll_alloc; A == sl_alloc; @@ -94,6 +97,7 @@ [{binary_alloc, 131072}, {std_alloc, 131072}, {ets_alloc, 131072}, + {fix_alloc, 131072}, {eheap_alloc, 524288}, {ll_alloc, 2097152}, {sl_alloc, 131072}, @@ -104,6 +108,7 @@ [{binary_alloc, 10}, {std_alloc, 10}, {ets_alloc, 10}, + {fix_alloc, 10}, {eheap_alloc, 10}, {ll_alloc, 0}, {sl_alloc, 10}, @@ -438,9 +443,6 @@ conf_alloc(#conf{format_to = FTO} = Conf, #alloc{name = A} = Alc) -> chk_xnote(Conf, Alc). chk_xnote(#conf{format_to = FTO}, - #alloc{name = fix_alloc}) -> - fcp(FTO, "Cannot be configured."); -chk_xnote(#conf{format_to = FTO}, #alloc{name = sys_alloc}) -> fcp(FTO, "Cannot be configured. Default malloc implementation used."); chk_xnote(#conf{format_to = FTO}, diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 89bcf23b5e..195f9fe1d3 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -319,12 +319,37 @@ point_of_no_return <pre> restart_new_emulator </pre> - <p>Shuts down the current emulator and starts a ne one. All - processes are terminated gracefully. The new release must still - be made permanent when the new emulator is up and running. - Otherwise, the old emulator is started in case of a emulator - restart. This instruction should be used when a new emulator is - introduced, or if a complete reboot of the system should be done.</p> + <p>This instruction is used when erts, kernel, stdlib or sasl is + upgraded. It shuts down the current emulator and starts a new + one. All processes are terminated gracefully, and the new + version of erts, kernel, stdlib and sasl are used when the + emulator restarts. Only one <c>restart_new_emulator</c> + instruction is allowed in the relup, and it shall be placed + first. <seealso marker="systools#make_relup/3">systools:make_relup3,4</seealso> + will ensure this when the relup is generated. The rest of the + relup script is executed after the restart as a part of the boot + script.</p> + <p>An info report will be written when the upgrade is + completed. To programatically find out if the upgrade is + complete, + call <seealso marker="release_handler#which_release/0"> + release_handler:which_releases</seealso> and check if the + expected release has status <c>current</c>.</p> + <p>The new release must still be made permanent after the upgrade + is completed. Otherwise, the old emulator is started in case of + an emulator restart.</p> + <pre> +restart_emulator + </pre> + <p>This instruction is similar to <c>restart_new_emulator</c>, + except it shall be placed at the end of the relup script. It is + not related to an upgrade of the emulator or the core + applications, but can be used by any application when a complete + reboot of the system is reqiured. When generating the + relup, <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso> + ensures that there is only one <c>restart_emulator</c> + instruction and that it is the last instruction of the + relup.</p> </section> <section> diff --git a/lib/sasl/doc/src/make.dep b/lib/sasl/doc/src/make.dep deleted file mode 100644 index 4843b7934a..0000000000 --- a/lib/sasl/doc/src/make.dep +++ /dev/null @@ -1,22 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: alarm_handler.tex appup.tex book.tex error_logging.tex \ - overload.tex part.tex rb.tex ref_man.tex rel.tex \ - release_handler.tex relup.tex sasl_app.tex \ - sasl_intro.tex script.tex systools.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 5ac0dc1acc..7f32100d4b 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -238,7 +238,7 @@ old reboot_old permanent </func> <func> <name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> - <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {error, Reason}</name> + <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name> <fsummary>Install a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> @@ -248,7 +248,8 @@ old reboot_old permanent <v> Timeout = default | infinity | int()>0</v> <v> Bool = boolean()</v> <v>Descr = term()</v> - <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | term()</v> + <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term()</v> + <v>App = atom()</v> </type> <desc> <p>Installs the specified version <c>Vsn</c> of the release. @@ -268,6 +269,15 @@ old reboot_old permanent <c>OtherVsn</c> and <c>Descr</c> are the version (<c>UpFromVsn</c> or <c>Vsn</c>) and description (<c>Descr1</c> or <c>Descr2</c>) as specified in the script.</p> + <p>If <c>{continue_after_restart,OtherVsn,Descr}</c> is + returned, it means that the emulator will be restarted + before the upgrade instructions are executed. This will + happen if the emulator or any of the applications kernel, + stdlib or sasl are updated. The new version of the emulator + and these core applications will execute after the restart, + but for all other applications the old versions will be + started and the upgrade will be performed as normal by + executing the upgrade instructions.</p> <p>If a recoverable error occurs, the function returns <c>{error,Reason}</c> and the original application specifications are restored. If a non-recoverable error @@ -325,6 +335,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). upgrade, but it will allow checks and purge to be executed in the background before the real upgrade is started.</p> </note> + <note> + <p>When upgrading the emulator from a version older than OTP + R15, there will be an attempt to load new application beam + code into the old emulator. In some cases, the new beam + format can not be read by the old emulator, and so the code + loading will fail and terminate the complete upgrade. To + overcome this problem, the new application code should be + compiled with the old emulator. See <seealso + marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> for more information about emulator + upgrade from pre OTP R15 versions.</p> + </note> </desc> </func> <func> @@ -431,6 +453,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <p>Returns all releases known to the release handler.</p> </desc> </func> + <func> + <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name> + <fsummary>Return all known releases of a specific status</fsummary> + <type> + <v>Name = Vsn = string()</v> + <v>Apps = ["App-Vsn"]</v> + <v>Status = unpacked | current | permanent | old</v> + </type> + <desc> + <p>Returns all releases known to the release handler of a specific status.</p> + </desc> + </func> </funcs> <section> @@ -442,7 +476,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). and evaluated exactly in the same way as <c>release_handler</c> does.</p> <warning> - <p>These function is primarily intended for simplified testing of + <p>These functions are primarily intended for simplified testing of <c>.appup</c> files. They are not run within the context of the <c>release_handler</c> process. They must therefore <em>not</em> be used together with calls to diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 8c1c327d74..fa2fcbf534 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -111,6 +111,11 @@ low-level instruction to restart the emulator is appended to the relup scripts. This ensures that a complete reboot of the system is done when the system is upgraded or downgraded.</p> + <p>If an upgrade includes a change from an emulator earlier + than OTP R15 to OTP R15 or later, the warning + <c>pre_R15_emulator_upgrade</c> is issued. See <seealso + marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> for more information about this.</p> <p>By default, errors and warnings are printed to tty and the function returns <c>ok</c> or <c>error</c>. If the option <c>silent</c> is provided, the function instead returns diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index bc08f94dff..4e8cb4628c 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -26,8 +26,9 @@ create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, - install_release/1, install_release/2, remove_release/1, - which_releases/0, make_permanent/1, reboot_old_release/1, + install_release/1, install_release/2, new_emulator_upgrade/2, + remove_release/1, which_releases/0, which_releases/1, + make_permanent/1, reboot_old_release/1, set_unpacked/2, set_removed/1, install_file/2]). -export([upgrade_app/2, downgrade_app/2, downgrade_app/3, upgrade_script/2, downgrade_script/3, @@ -40,7 +41,7 @@ %% Internal exports, a client release_handler may call this functions. -export([do_write_release/3, do_copy_file/2, do_copy_files/2, do_copy_files/1, do_rename_files/1, do_remove_files/1, - do_write_file/2, do_ensure_RELEASES/1]). + remove_file/1, do_write_file/2, do_ensure_RELEASES/1]). -record(state, {unpurged = [], root, @@ -61,10 +62,11 @@ %% remove - %% current make_permanent permanent %% install other old +%% restart node unpacked %% remove - %% permanent make other permanent old %% install permanent -%% old reboot permanen +%% old reboot_old permanent %% install current %% remove - %%----------------------------------------------------------------- @@ -74,6 +76,14 @@ -define(timeout, 10000). %%----------------------------------------------------------------- +%% The version set on the temporary release that will be used when the +%% emulator is upgraded. +-define(tmp_vsn(__BaseVsn__), "__new_emulator__"++__BaseVsn__). + + + + +%%----------------------------------------------------------------- %% Assumes the following file structure: %% root --- lib --- Appl-Vsn1 --- <src> %% | | |- ebin @@ -183,11 +193,15 @@ check_check_install_options([],Purge) -> %%----------------------------------------------------------------- %% Purpose: Executes the relup script for the specified version. %% The release must be unpacked. -%% Returns: {ok, FromVsn, Descr} | {error, Reason} +%% Returns: {ok, FromVsn, Descr} | +%% {continue_after_restart, FromVsn, Descr} | +%% {error, Reason} %% Reason = {already_installed, Vsn} | %% {bad_relup_file, RelFile} | %% {no_such_release, Vsn} | %% {no_such_from_vsn, Vsn} | +%% {could_not_create_hybrid_boot,Why} | +%% {missing_base_app,Vsn,App} | %% {illegal_option, Opt}} | %% exit_reason() %%----------------------------------------------------------------- @@ -230,6 +244,21 @@ check_timeout(Int) when is_integer(Int), Int > 0 -> true; check_timeout(_Else) -> false. %%----------------------------------------------------------------- +%% Purpose: Called by boot script after emulator is restarted due to +%% new erts version. +%% Returns: Same as install_release/2 +%% If this crashes, the emulator restart will fail +%% (since the function is called from the boot script) +%% and there will be a rollback. +%%----------------------------------------------------------------- +new_emulator_upgrade(Vsn, Opts) -> + Result = call({install_release, Vsn, reboot, Opts}), + error_logger:info_msg( + "~p:install_release(~p,~p) completed after node restart " + "with new emulator version~nResult: ~p~n",[?MODULE,Vsn,Opts,Result]), + Result. + +%%----------------------------------------------------------------- %% Purpose: Makes the specified release version be the one that is %% used when the system starts (or restarts). %% The release must be installed (not unpacked). @@ -305,6 +334,14 @@ which_releases() -> call(which_releases). %%----------------------------------------------------------------- +%% Returns: [{Name, Vsn, [LibName], Status}] +%% Status = unpacked | current | permanent | old +%%----------------------------------------------------------------- +which_releases(Status) -> + Releases = which_releases(), + get_releases_with_status(Releases, Status, []). + +%%----------------------------------------------------------------- %% check_script(Script, LibDirs) -> ok | {error, Reason} %%----------------------------------------------------------------- check_script(Script, LibDirs) -> @@ -313,7 +350,7 @@ check_script(Script, LibDirs) -> %%----------------------------------------------------------------- %% eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> %% {ok, UnPurged} | -%% restart_new_emulator | +%% restart_emulator | %% {error, Error} %% {'EXIT', Reason} %% If sync_nodes is present, the calling process must have called @@ -350,7 +387,7 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %%----------------------------------------------------------------- %% Func: upgrade_app(App, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -370,7 +407,7 @@ upgrade_app(App, NewDir) -> %%----------------------------------------------------------------- %% Func: downgrade_app(App, Dir) %% downgrade_app(App, Vsn, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -578,7 +615,7 @@ handle_call({check_install_release, Vsn, Purge}, _From, S) -> handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> NS = resend_sync_nodes(S), case catch do_install_release(S, Vsn, Opts) of - {ok, NewReleases, CurrentVsn, Descr} -> + {ok, NewReleases, [], CurrentVsn, Descr} -> {reply, {ok, CurrentVsn, Descr}, NS#state{releases=NewReleases}}; {ok, NewReleases, Unpurged, CurrentVsn, Descr} -> Timer = @@ -593,10 +630,14 @@ handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> {reply, {ok, CurrentVsn, Descr}, NewS}; {error, Reason} -> {reply, {error, Reason}, NS}; - {restart_new_emulator, CurrentVsn, Descr} -> + {restart_emulator, CurrentVsn, Descr} -> gen_server:reply(From, {ok, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; + {restart_new_emulator, CurrentVsn, Descr} -> + gen_server:reply(From, {continue_after_restart, CurrentVsn, Descr}), + init:reboot(), + {noreply, NS}; {'EXIT', Reason} -> io:format("release_handler:" "install_release(Vsn=~p Opts=~p) failed, " @@ -941,7 +982,38 @@ do_install_release(#state{start_prg = StartPrg, {value, Release} -> LatestRelease = get_latest_release(Releases), case get_rh_script(LatestRelease, Release, RelDir, Masters) of + {ok, {_CurrentVsn, _Descr, [restart_new_emulator|_Script]}} + when Static == true -> + throw(static_emulator); + {ok, {CurrentVsn, Descr, [restart_new_emulator|_Script]}} -> + %% This will only happen if the upgrade includes + %% an emulator upgrade (and it is not a downgrade) + %% - then the new emulator must be started before + %% new code can be loaded. + %% Create a temporary release which includes new + %% emulator, kernel, stdlib and sasl - and old + %% versions of other applications. + {TmpVsn,TmpRelease} = + new_emulator_make_tmp_release(LatestRelease,Release, + RelDir,Opts,Masters), + NReleases = [TmpRelease|Releases], + + %% Then uppgrade to the temporary release. + %% The rest of the upgrade will continue after the restart + prepare_restart_new_emulator(StartPrg, RootDir, + RelDir, TmpVsn, TmpRelease, + NReleases, Masters), + {restart_new_emulator, CurrentVsn, Descr}; {ok, {CurrentVsn, Descr, Script}} -> + %% In case there has been an emulator upgrade, + %% remove the temporary release + NReleases = + new_emulator_rm_tmp_release( + LatestRelease#release.vsn, + LatestRelease#release.erts_vsn, + Vsn,RelDir,Releases,Masters), + + %% Then execute the relup script mon_nodes(true), EnvBefore = application_controller:prep_config_change(), Apps = change_appl_data(RelDir, Release, Masters), @@ -949,31 +1021,19 @@ do_install_release(#state{start_prg = StartPrg, NewLibs = get_new_libs(LatestRelease#release.libs, Release#release.libs), case eval_script(Script, Apps, LibDirs, NewLibs, Opts) of - {ok, []} -> - application_controller:config_change(EnvBefore), - mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, CurrentVsn, Descr}; {ok, Unpurged} -> application_controller:config_change(EnvBefore), mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, Unpurged, CurrentVsn, Descr}; - restart_new_emulator when Static == true -> + NReleases1 = set_status(Vsn, current, NReleases), + {ok, NReleases1, Unpurged, CurrentVsn, Descr}; + restart_emulator when Static == true -> throw(static_emulator); - restart_new_emulator -> + restart_emulator -> mon_nodes(false), - {value, PermanentRelease} = - lists:keysearch(permanent, #release.status, - Releases), - NReleases = set_status(Vsn, current, Releases), - NReleases2 = set_status(Vsn,tmp_current,NReleases), - write_releases(RelDir, NReleases2, Masters), prepare_restart_new_emulator(StartPrg, RootDir, - RelDir, Release, - PermanentRelease, - Masters), - {restart_new_emulator, CurrentVsn, Descr}; + RelDir, Vsn, Release, + NReleases, Masters), + {restart_emulator, CurrentVsn, Descr}; Else -> application_controller:config_change(EnvBefore), mon_nodes(false), @@ -986,6 +1046,145 @@ do_install_release(#state{start_prg = StartPrg, {error, {no_such_release, Vsn}} end. +new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) -> + CurrentVsn = CurrentRelease#release.vsn, + ToVsn = ToRelease#release.vsn, + TmpVsn = ?tmp_vsn(CurrentVsn), + BaseApps = [kernel,stdlib,sasl], + BaseLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- ToRelease#release.libs, + lists:member(App,BaseApps)], + check_base_libs(BaseLibs,ToVsn), + OldBaseLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- CurrentRelease#release.libs, + lists:member(App,BaseApps)], + check_base_libs(OldBaseLibs,CurrentVsn), + RestLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- CurrentRelease#release.libs, + not lists:member(App,BaseApps)], + TmpRelease = CurrentRelease#release{vsn=TmpVsn, + erts_vsn=ToRelease#release.erts_vsn, + libs = BaseLibs ++ RestLibs, + status = unpacked}, + new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs, + RelDir,Opts,Masters), + new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters), + {TmpVsn,TmpRelease}. + +check_base_libs([_,_,_]=BaseLibs,_Vsn) -> + [Kernel,Sasl,Stdlib] = lists:keysort(1,BaseLibs), + [Kernel,Stdlib,Sasl]; +check_base_libs(SomeMissing,Vsn) -> + find_missing(SomeMissing,[kernel,stdlib,sasl],Vsn). + +find_missing(SomeMissing,[H|T],Vsn) -> + case lists:keymember(H,1,SomeMissing) of + true -> + find_missing(SomeMissing,T,Vsn); + false -> + throw({error,{missing_base_app,Vsn,H}}) + end. + +new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) -> + FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]), + ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]), + TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]), + ensure_dir(TmpBootFile,Masters), + Args = [ToVsn,Opts], + {ok,FromBoot} = read_file(FromBootFile,Masters), + {ok,ToBoot} = read_file(ToBootFile,Masters), + [KernelPath,SaslPath,StdlibPath] = + [filename:join(Path,ebin) || {_,_,Path} <- lists:keysort(1,BaseLibs)], + Paths = {KernelPath,StdlibPath,SaslPath}, + case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Paths,Args) of + {ok,TmpBoot} -> + write_file(TmpBootFile,TmpBoot,Masters); + {error,Reason} -> + throw({error,{could_not_create_hybrid_boot,Reason}}) + end. + +new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) -> + FromFile = filename:join([RelDir,CurrentVsn,"sys.config"]), + ToFile = filename:join([RelDir,ToVsn,"sys.config"]), + TmpFile = filename:join([RelDir,TmpVsn,"sys.config"]), + + FromConfig = + case consult(FromFile,Masters) of + {ok,[FC]} -> + FC; + {error,Error1} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,FromFile,Error1]), + [] + end, + + [Kernel,Stdlib,Sasl] = + case consult(ToFile,Masters) of + {ok,[ToConfig]} -> + [lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]]; + {error,Error2} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,ToFile,Error2]), + [false,false,false] + end, + + Config1 = replace_config(kernel,FromConfig,Kernel), + Config2 = replace_config(stdlib,Config1,Stdlib), + Config3 = replace_config(sasl,Config2,Sasl), + + ConfigStr = io_lib:format("~p.~n",[Config3]), + write_file(TmpFile,ConfigStr,Masters). + +%% Take the configuration for application App from the new config and +%% insert in the old config. +%% If no entry exists in the new config, then delete the entry (if it exists) +%% from the old config. +%% If entry exists in the new config, but not in the old config, then +%% add the entry. +replace_config(App,Config,false) -> + lists:keydelete(App,1,Config); +replace_config(App,Config,AppConfig) -> + lists:keystore(App,1,Config,AppConfig). + +%% Remove all files related to the temporary release +new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn, + RelDir,Releases,Masters) -> + case os:type() of + {win32, nt} -> + rename_tmp_service(EVsn,TmpVsn,NewVsn); + _ -> + ok + end, + remove_dir(filename:join(RelDir,TmpVsn),Masters), + lists:keydelete(TmpVsn,#release.vsn,Releases); +new_emulator_rm_tmp_release(_,_,_,_,Releases,_) -> + Releases. + +%% Rename the tempoarary service (for erts ugprade) to the real ToVsn +rename_tmp_service(EVsn,TmpVsn,NewVsn) -> + FromName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn, + ToName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ NewVsn, + case erlsrv:get_service(EVsn,ToName) of + {error, _Error} -> + ok; + _Data -> + erlsrv:remove_service(ToName) + end, + rename_service(EVsn,FromName,ToName). + + +%% Rename a service and check that it succeeded +rename_service(EVsn,FromName,ToName) -> + case erlsrv:rename_service(EVsn,FromName,ToName) of + {ok,_} -> + case erlsrv:get_service(EVsn,ToName) of + {error,Error1} -> + throw({error,Error1}); + _Data2 -> + ok + end; + Error2 -> + throw({error,{service_rename_failed, Error2}}) + end. + + %%% This code chunk updates the services in one of two ways, %%% Either the emulator is restarted, in which case the old service %%% is to be removed and the new enabled, or the emulator is NOT restarted @@ -1002,26 +1201,16 @@ do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) -> %% rename. case os:getenv("ERLSRV_SERVICE_NAME") == PermName of true -> - case erlsrv:rename_service(EVsn,PermName,Name) of - {ok,_} -> - case erlsrv:get_service(EVsn,Name) of - {error,Error2} -> - throw({error,Error2}); - _Data2 -> - %% The interfaces for doing this are - %% NOT published and may be subject to - %% change. Do NOT do this anywhere else! - - os:putenv("ERLSRV_SERVICE_NAME", Name), - - %% Restart heart port program, this - %% function is only to be used here. - heart:cycle(), - ok - end; - Error3 -> - throw({error,{service_rename_failed, Error3}}) - end; + rename_service(EVsn,PermName,Name), + %% The interfaces for doing this are + %% NOT published and may be subject to + %% change. Do NOT do this anywhere else! + + os:putenv("ERLSRV_SERVICE_NAME", Name), + + %% Restart heart port program, this + %% function is only to be used here. + heart:cycle(); false -> throw({error,service_name_missmatch}) end; @@ -1260,21 +1449,31 @@ do_set_removed(RelDir, Vsn, Releases, Masters) -> %% corresponding relup instructions, we check if it's possible to %% downgrade from CurrentVsn to ToVsn. %%----------------------------------------------------------------- +get_rh_script(#release{vsn = ?tmp_vsn(CurrentVsn)}, + #release{vsn = ToVsn}, + RelDir, + Masters) -> + {ok,{Vsn,Descr,[restart_new_emulator|Script]}} = + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters), + {ok,{Vsn,Descr,Script}}; get_rh_script(#release{vsn = CurrentVsn}, - #release{vsn = Vsn}, + #release{vsn = ToVsn}, RelDir, Masters) -> - Relup = filename:join([RelDir, Vsn, "relup"]), - case try_upgrade(Vsn, CurrentVsn, Relup, Masters) of + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters). + +do_get_rh_script(CurrentVsn, ToVsn, RelDir, Masters) -> + Relup = filename:join([RelDir, ToVsn, "relup"]), + case try_upgrade(ToVsn, CurrentVsn, Relup, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> Relup2 = filename:join([RelDir, CurrentVsn,"relup"]), - case try_downgrade(Vsn, CurrentVsn, Relup2, Masters) of + case try_downgrade(ToVsn, CurrentVsn, Relup2, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> - throw({error, {no_matching_relup, Vsn, CurrentVsn}}) + throw({error, {no_matching_relup, ToVsn, CurrentVsn}}) end end. @@ -1487,6 +1686,15 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn}, %% restart is performed by calling init:reboot() higher up. %%----------------------------------------------------------------- prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Vsn, Release, Releases, Masters) -> + {value, PRelease} = lists:keysearch(permanent, #release.status,Releases), + NReleases1 = set_status(Vsn, current, Releases), + NReleases2 = set_status(Vsn,tmp_current,NReleases1), + write_releases(RelDir, NReleases2, Masters), + prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Release, PRelease, Masters). + +prepare_restart_new_emulator(StartPrg, RootDir, RelDir, Release, PRelease, Masters) -> #release{erts_vsn = EVsn, vsn = Vsn} = Release, Data = EVsn ++ " " ++ Vsn, @@ -1512,19 +1720,10 @@ check_start_prg({do_check, StartPrg}, Masters) -> check_start_prg({_, StartPrg}, _) -> StartPrg. -write_new_start_erl(Data, RelDir, false) -> - DataFile = filename:join([RelDir, "new_start_erl.data"]), - case do_write_file(DataFile, Data) of - ok -> DataFile; - Error -> throw(Error) - end; write_new_start_erl(Data, RelDir, Masters) -> DataFile = filename:join([RelDir, "new_start_erl.data"]), - case at_all_masters(Masters, ?MODULE, do_write_file, - [DataFile, Data]) of - ok -> DataFile; - Error -> throw(Error) - end. + write_file(DataFile, Data, Masters), + DataFile. %%----------------------------------------------------------------- %% When a new emulator shall be restarted, the current release @@ -1538,27 +1737,41 @@ write_new_start_erl(Data, RelDir, Masters) -> %% If the release is made permanent, this is written to disk. %%----------------------------------------------------------------- transform_release(ReleaseDir, Releases, Masters) -> - F = fun(Release) when Release#release.status == tmp_current -> - Release#release{status = unpacked}; - (Release) -> Release - end, - case lists:map(F, Releases) of - Releases -> - Releases; - DReleases -> + case init:script_id() of + {Name, ?tmp_vsn(_)=TmpVsn} -> + %% This is was a reboot due to a new emulator version. The + %% current release is a temporary internal release, which + %% must be removed. It is the "real new release" that is + %% set to unpacked on disk and current in memory. + DReleases = lists:keydelete(TmpVsn,#release.vsn,Releases), write_releases(ReleaseDir, DReleases, Masters), - F1 = fun(Release) when Release#release.status == tmp_current -> - case init:script_id() of - {_Name, Vsn} when Release#release.vsn == Vsn -> - Release#release{status = current}; - _ -> - Release#release{status = unpacked} - end; - (Release) -> Release - end, - lists:map(F1, Releases) + set_current({Name,TmpVsn},Releases); + ScriptId -> + F = fun(Release) when Release#release.status == tmp_current -> + Release#release{status = unpacked}; + (Release) -> Release + end, + case lists:map(F, Releases) of + Releases -> + Releases; + DReleases -> + write_releases(ReleaseDir, DReleases, Masters), + set_current(ScriptId, Releases) + end end. +set_current(ScriptId, Releases) -> + F1 = fun(Release) when Release#release.status == tmp_current -> + case ScriptId of + {_Name,Vsn} when Release#release.vsn == Vsn -> + Release#release{status = current}; + _ -> + Release#release{status = unpacked} + end; + (Release) -> Release + end, + lists:map(F1, Releases). + %%----------------------------------------------------------------- %% Functions handling files, RELEASES, start_erl.data etc. %% This functions consider if the release_handler is a client and @@ -1617,12 +1830,25 @@ extract_tar(Root, Tar) -> throw({error, {cannot_extract_file, Name, Reason}}) end. -write_releases(Dir, NewReleases, false) -> +write_releases(Dir, Releases, Masters) -> + %% We must never write 'current' to disk, since this will confuse + %% us after a node restart - since we would then have a permanent + %% release running, but state set to current for a non-running + %% release. + NewReleases = lists:zf(fun(Release) when Release#release.status == current -> + {true, Release#release{status = unpacked}}; + (_) -> + true + end, Releases), + write_releases_1(Dir, NewReleases, Masters). + + +write_releases_1(Dir, NewReleases, false) -> case do_write_release(Dir, "RELEASES", NewReleases) of ok -> ok; Error -> throw(Error) end; -write_releases(Dir, NewReleases, Masters) -> +write_releases_1(Dir, NewReleases, Masters) -> all_masters(Masters), write_releases_m(Dir, NewReleases, Masters). @@ -1844,6 +2070,37 @@ read_file(File, false) -> read_file(File, Masters) -> read_master(Masters, File). +write_file(File, Data, false) -> + case file:write_file(File, Data) of + ok -> ok; + Error -> throw(Error) + end; +write_file(File, Data, Masters) -> + case at_all_masters(Masters, file, write_file, [File, Data]) of + ok -> ok; + Error -> throw(Error) + end. + +ensure_dir(File, false) -> + case filelib:ensure_dir(File) of + ok -> ok; + Error -> throw(Error) + end; +ensure_dir(File, Masters) -> + case at_all_masters(Masters,filelib,ensure_dir,[File]) of + ok -> ok; + Error -> throw(Error) + end. + +remove_dir(Dir, false) -> + remove_file(Dir); +remove_dir(Dir, Masters) -> + case at_all_masters(Masters,?MODULE,remove_file,[Dir]) of + ok -> ok; + Error -> throw(Error) + end. + + %% Ignore status of each delete ! remove_files(Master, Files, Masters) -> takewhile(Master, Masters, ?MODULE, do_remove_files, [Files]). @@ -2010,3 +2267,14 @@ get_new_libs([{App,Vsn,_LibDir}|CurrentLibs], NewLibs) -> end; get_new_libs([],_) -> []. + +%%----------------------------------------------------------------- +%% Return a list of releases witch a specific status +%%----------------------------------------------------------------- +get_releases_with_status([], _, Acc) -> + Acc; +get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail], + Status, Acc) when ReleaseStatus == Status -> + get_releases_with_status(Tail, Status, [Head | Acc]); +get_releases_with_status([_ | Tail], Status, Acc) -> + get_releases_with_status(Tail, Status, Acc). diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 8d0baf3ab1..b4b288646f 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -47,26 +47,38 @@ %%%----------------------------------------------------------------- %%% This is a low-level release handler. %%%----------------------------------------------------------------- +check_script([restart_new_emulator|Script], LibDirs) -> + %% There is no need to check for old processes, since the node + %% will be restarted before anything else happens. + do_check_script(Script, LibDirs, []); check_script(Script, LibDirs) -> case catch check_old_processes(Script,soft_purge) of {ok, PurgeMods} -> - {Before, _After} = split_instructions(Script), - case catch lists:foldl(fun(Instruction, EvalState1) -> - eval(Instruction, EvalState1) - end, - #eval_state{libdirs = LibDirs}, - Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - {ok,PurgeMods}; - {error, Error} -> - {error, Error}; - Other -> - {error, Other} - end; + do_check_script(Script, LibDirs, PurgeMods); {error, Mod} -> {error, {old_processes, Mod}} end. +do_check_script(Script, LibDirs, PurgeMods) -> + {Before, After} = split_instructions(Script), + case catch lists:foldl(fun(Instruction, EvalState1) -> + eval(Instruction, EvalState1) + end, + #eval_state{libdirs = LibDirs}, + Before) of + EvalState2 when is_record(EvalState2, eval_state) -> + case catch syntax_check_script(After) of + ok -> + {ok,PurgeMods}; + Other -> + {error,Other} + end; + {error, Error} -> + {error, Error}; + Other -> + {error, Other} + end. + %% eval_script/1 - For testing only - no apps added, just testing instructions eval_script(Script) -> eval_script(Script, [], [], [], []). @@ -83,22 +95,30 @@ eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> newlibs = NewLibs, opts = Opts}, Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - case catch lists:foldl(fun(Instruction, EvalState3) -> - eval(Instruction, EvalState3) - end, - EvalState2, - After) of - EvalState4 when is_record(EvalState4, eval_state) -> - {ok, EvalState4#eval_state.unpurged}; - restart_new_emulator -> - restart_new_emulator; - Error -> - {'EXIT', Error} - end; - {error, Error} -> {error, Error}; - Other -> {error, Other} - end; + EvalState2 when is_record(EvalState2, eval_state) -> + case catch syntax_check_script(After) of + ok -> + case catch lists:foldl( + fun(Instruction, EvalState3) -> + eval(Instruction, + EvalState3) + end, + EvalState2, + After) of + EvalState4 + when is_record(EvalState4, eval_state) -> + {ok, EvalState4#eval_state.unpurged}; + restart_emulator -> + restart_emulator; + Error -> + {'EXIT', Error} + end; + Other -> + {error,Other} + end; + {error, Error} -> {error, Error}; + Other -> {error, Other} + end; {error, Mod} -> {error, {old_processes, Mod}} end. @@ -174,6 +194,42 @@ do_check_old_code(Mod,Procs) -> [Mod]. +%% Check the last part of the script, i.e. the part after point_of_no_return. +%% More or less a syntax check in case the script was handwritten. +syntax_check_script([point_of_no_return | Script]) -> + syntax_check_script(Script); +syntax_check_script([{load, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{remove, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{purge, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{suspend, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{resume, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{stop, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{start, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{apply, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([restart_emulator | Script]) -> + syntax_check_script(Script); +syntax_check_script([Illegal | _Script]) -> + throw({illegal_instruction_after_point_of_no_return,Illegal}); +syntax_check_script([]) -> + ok. + + %%----------------------------------------------------------------- %% An unpurged module is a module for which there exist an old %% version of the code. This should only be the case if there are @@ -243,7 +299,7 @@ do_check_old_code(Mod,Procs) -> %% must also exectue the same line. Waits for all these nodes to get %% to this line. %% point_of_no_return -%% restart_new_emulator +%% restart_emulator %% {stop_application, Appl} - Impl with apply %% {unload_application, Appl} - Impl with {remove..} %% {load_application, Appl} - Impl with {load..} @@ -402,8 +458,8 @@ eval({sync_nodes, Id, Nodes}, EvalState) -> eval({apply, {M, F, A}}, EvalState) -> apply(M, F, A), EvalState; -eval(restart_new_emulator, _EvalState) -> - throw(restart_new_emulator). +eval(restart_emulator, _EvalState) -> + throw(restart_emulator). get_opt(Tag, EvalState, Default) -> case lists:keysearch(Tag, 1, EvalState#eval_state.opts) of diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index 64c653a4e5..ce4aa1f8f8 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -1,25 +1,27 @@ -%% +%% -*- erlang -*- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% 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 online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% -%% %CopyrightEnd% %% - +%% %CopyrightEnd% {"%VSN%", - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}], - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}] + %% Up from - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13B-R14B03 + %% Down to - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13B-R14B03 }. diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 7f400f5cce..ce37f3c2ce 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -31,6 +31,8 @@ -export([read_application/4]). +-export([make_hybrid_boot/5]). + -import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1, append/1, foldl/3, member/2, foreach/2]). @@ -162,6 +164,118 @@ return({error,Mod,Error},_,Flags) -> error end. + +%%----------------------------------------------------------------- +%% Make hybrid boot file for upgrading emulator. The resulting boot +%% file is a combination of the two input files, where kernel, stdlib +%% and sasl versions are taken from the second file (the boot file of +%% the new release), and all other application versions from the first +%% file (the boot file of the old release). +%% +%% The most important thing that can fail here is that the input boot +%% files do not contain all three base applications - kernel, stdlib +%% and sasl. +%% +%% TmpVsn = string(), +%% Paths = {KernelPath,StdlibPath,SaslPath} +%% Returns {ok,Boot} | {error,Reason} +%% Boot1 = Boot2 = Boot = binary() +%% Reason = {app_not_found,App} | {app_not_replaced,App} +%% App = kernel | stdlib | sasl +make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> + catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args). +do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> + {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1), + {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2), + MatchPaths = get_regexp_path(Paths), + NewScript1 = replace_paths(Script1,MatchPaths), + {Kernel,Stdlib,Sasl} = get_apps(Script2,undefined,undefined,undefined), + NewScript2 = replace_apps(NewScript1,Kernel,Stdlib,Sasl), + NewScript3 = add_apply_upgrade(NewScript2,Args), + Boot = term_to_binary({script,{RelName2,TmpVsn},NewScript3}), + {ok,Boot}. + +%% For each app, compile a regexp that can be used for finding its path +get_regexp_path({KernelPath,StdlibPath,SaslPath}) -> + {ok,KernelMP} = re:compile("kernel-[0-9\.]+",[unicode]), + {ok,StdlibMP} = re:compile("stdlib-[0-9\.]+",[unicode]), + {ok,SaslMP} = re:compile("sasl-[0-9\.]+",[unicode]), + [{KernelMP,KernelPath},{StdlibMP,StdlibPath},{SaslMP,SaslPath}]. + +%% For each path in the script, check if it matches any of the MPs +%% found above, and if so replace it with the correct new path. +replace_paths([{path,Path}|Script],MatchPaths) -> + [{path,replace_path(Path,MatchPaths)}|replace_paths(Script,MatchPaths)]; +replace_paths([Stuff|Script],MatchPaths) -> + [Stuff|replace_paths(Script,MatchPaths)]; +replace_paths([],_) -> + []. + +replace_path([Path|Paths],MatchPaths) -> + [do_replace_path(Path,MatchPaths)|replace_path(Paths,MatchPaths)]; +replace_path([],_) -> + []. + +do_replace_path(Path,[{MP,ReplacePath}|MatchPaths]) -> + case re:run(Path,MP,[{capture,none}]) of + nomatch -> do_replace_path(Path,MatchPaths); + match -> ReplacePath + end; +do_replace_path(Path,[]) -> + Path. + +%% Return the entries for loading the three base applications +get_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}=Kernel| + Script],_,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,stdlib,_}]}}=Stdlib|Script], + Kernel,_,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,sasl,_}]}}=Sasl|_Script], + Kernel,Stdlib,_) -> + {Kernel,Stdlib,Sasl}; +get_apps([_|Script],Kernel,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([],undefined,_,_) -> + throw({error,{app_not_found,kernel}}); +get_apps([],_,undefined,_) -> + throw({error,{app_not_found,stdlib}}); +get_apps([],_,_,undefined) -> + throw({error,{app_not_found,sasl}}). + + +%% Replace the entries for loading the base applications +replace_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}| + Script],Kernel,Stdlib,Sasl) -> + [Kernel|replace_apps(Script,undefined,Stdlib,Sasl)]; +replace_apps([{apply,{application,load,[{application,stdlib,_}]}}|Script], + Kernel,Stdlib,Sasl) -> + [Stdlib|replace_apps(Script,Kernel,undefined,Sasl)]; +replace_apps([{apply,{application,load,[{application,sasl,_}]}}|Script], + _Kernel,_Stdlib,Sasl) -> + [Sasl|Script]; +replace_apps([Stuff|Script],Kernel,Stdlib,Sasl) -> + [Stuff|replace_apps(Script,Kernel,Stdlib,Sasl)]; +replace_apps([],undefined,undefined,_) -> + throw({error,{app_not_replaced,sasl}}); +replace_apps([],undefined,_,_) -> + throw({error,{app_not_replaced,stdlib}}); +replace_apps([],_,_,_) -> + throw({error,{app_not_replaced,kernel}}). + + +%% Finally add an apply of release_handler:new_emulator_upgrade - which will +%% complete the execution of the upgrade script (relup). +add_apply_upgrade(Script,Args) -> + [{progress, started} | RevScript] = lists:reverse(Script), + lists:reverse([{progress,started}, + {apply,{release_handler,new_emulator_upgrade,Args}} | + RevScript]). + + + %%----------------------------------------------------------------- %% Create a release package from a release file. %% Options is a list of {path, Path} | silent | @@ -250,13 +364,13 @@ get_release(File, Path, ModTestP, Machine) -> end. get_release1(File, Path, ModTestP, Machine) -> - {ok, Release} = read_release(File, Path), + {ok, Release, Warnings1} = read_release(File, Path), {ok, Appls0} = collect_applications(Release, Path), {ok, Appls1} = check_applications(Appls0), {ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121 - {ok, Warnings} = check_modules(Appls2, Path, ModTestP, Machine), + {ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine), {ok, Appls} = sort_appls(Appls2), - {ok, Release, Appls, Warnings}. + {ok, Release, Appls, Warnings1 ++ Warnings2}. %%______________________________________________________________________ %% read_release(File, Path) -> {ok, #release} | throw({error, What}) @@ -271,11 +385,12 @@ read_release(File, Path) -> check_rel(Release) -> case catch check_rel1(Release) of - {ok, {Name,Vsn,Evsn,Appl,Incl}} -> + {ok, {Name,Vsn,Evsn,Appl,Incl}, Ws} -> {ok, #release{name=Name, vsn=Vsn, erts_vsn=Evsn, applications=Appl, - incl_apps=Incl}}; + incl_apps=Incl}, + Ws}; {error, Error} -> throw({error,?MODULE,Error}); Error -> @@ -286,8 +401,8 @@ check_rel1({release,{Name,Vsn},{erts,EVsn},Appl}) when is_list(Appl) -> check_name(Name), check_vsn(Vsn), check_evsn(EVsn), - {Appls,Incls} = check_appl(Appl), - {ok, {Name,Vsn,EVsn,Appls,Incls}}; + {{Appls,Incls},Ws} = check_appl(Appl), + {ok, {Name,Vsn,EVsn,Appls,Incls},Ws}; check_rel1(_) -> {error, badly_formatted_release}. @@ -340,8 +455,8 @@ check_appl(Appl) -> end, Appl) of [] -> - mandatory_applications(Appl), - split_app_incl(Appl); + {ok,Ws} = mandatory_applications(Appl), + {split_app_incl(Appl),Ws}; Illegal -> throw({error, {illegal_applications,Illegal}}) end. @@ -352,7 +467,12 @@ mandatory_applications(Appl) -> Mand = mandatory_applications(), case filter(fun(X) -> member(X, AppNames) end, Mand) of Mand -> - ok; + case member(sasl,AppNames) of + true -> + {ok,[]}; + _ -> + {ok, [{warning,missing_sasl}]} + end; _ -> throw({error, {missing_mandatory_app, Mand}}) end. @@ -2198,5 +2318,9 @@ form_warn(Prefix, {exref_undef, Undef}) -> [Prefix,M,F,A]) end, map(F, Undef); +form_warn(Prefix, missing_sasl) -> + io_lib:format("~s: Missing application sasl. " + "Can not upgrade with this release~n", + [Prefix]); form_warn(Prefix, What) -> io_lib:format("~s ~p~n", [Prefix,What]). diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index daadb79967..c16f6aa845 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -54,6 +54,7 @@ %% {sync_nodes, Id, Nodes} %% {apply, {M, F, A}} %% restart_new_emulator +%% restart_emulator %%----------------------------------------------------------------- %% High-level instructions that contain dependencies @@ -144,7 +145,10 @@ translate_merged_script(Mode, Script, Appls, PreAppls) -> {Before2, After2} = translate_dependent_instrs(Mode, Before1, After1, Appls), Before3 = merge_load_object_code(Before2), - NewScript = Before3 ++ [point_of_no_return | After2], + + {Before4,After4} = sort_emulator_restart(Mode,Before3,After2), + NewScript = Before4 ++ [point_of_no_return | After4], + check_syntax(NewScript), {ok, NewScript}. @@ -699,6 +703,39 @@ mlo([{load_object_code, {Lib, LibVsn, Mods}} | T]) -> mlo([]) -> []. %%----------------------------------------------------------------- +%% RESTART EMULATOR +%% ----------------------------------------------------------------- +%% ----------------------------------------------------------------- +%% Check if there are any 'restart_new_emulator' instructions (i.e. if +%% the emulator or core application version is changed). If so, this +%% must be done first for upgrade and last for downgrade. +%% Check if there are any 'restart_emulator' instructions, if so +%% remove all and place one the end. +%% ----------------------------------------------------------------- +sort_emulator_restart(Mode,Before,After) -> + {Before1,After1} = + case filter_out(restart_new_emulator, After) of + After -> + {Before,After}; + A1 when Mode==up -> + {[restart_new_emulator|Before],A1}; + A1 when Mode==dn -> + {Before,A1++[restart_emulator]} + end, + After2 = + case filter_out(restart_emulator, After1) of + After1 -> + After1; + A2 -> + A2++[restart_emulator] + end, + {Before1,After2}. + + +filter_out(What,List) -> + lists:filter(fun(X) when X=:=What -> false; (_) -> true end, List). + +%%----------------------------------------------------------------- %% SYNTAX CHECK %%----------------------------------------------------------------- %%----------------------------------------------------------------- @@ -817,6 +854,7 @@ check_op({apply, {M, F, A}}) -> check_func(F), check_args(A); check_op(restart_new_emulator) -> ok; +check_op(restart_emulator) -> ok; check_op(X) -> throw({error, {bad_instruction, X}}). check_mod(Mod) when is_atom(Mod) -> ok; diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 6d9e922900..7fb623bb85 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -112,6 +112,11 @@ -export([mk_relup/3, mk_relup/4, format_error/1, format_warning/1]). -include("systools.hrl"). +-define(R15_SASL_VSN,"2.2"). + +%% For test purposes only - used by kernel, stdlib and sasl tests +-export([appup_search_for_version/2]). + %%----------------------------------------------------------------- %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) -> Ret @@ -200,7 +205,13 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) -> %% TopRel = #release %% NameVsnApps = [{{Name, Vsn}, #application}] {ok, TopRel, NameVsnApps, Ws0} -> - %% + case lists:member({warning,missing_sasl},Ws0) of + true -> + throw({error,?MODULE,{missing_sasl,TopRel}}); + false -> + ok + end, + %% TopApps = [#application] TopApps = lists:map(fun({_, App}) -> App end, NameVsnApps), @@ -247,7 +258,21 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), + {BaseRel, {BaseNameVsns, BaseApps}, Ws0} = + case systools_make:get_release(BaseRelFile, Path) of + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NameVsnApps = [{{Name,Vsn},#application}] + %% Gives two lists - [{Name,Vsn}] and [#application] + {BR,lists:unzip(NameVsnApps),Warns} + end; + Other1 -> + throw(Other1) + end, + %% %% BaseRel = #release @@ -257,29 +282,23 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, %% application, one for each added applications, and one for %% each removed applications. %% - {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws, []), + {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws0++Ws, []), {RUs2, Ws2} = create_add_app_scripts(BaseRel, TopRel, RUs1, Ws1), {RUs3, Ws3} = create_remove_app_scripts(BaseRel, TopRel, RUs2, Ws2), - {RUs4, Ws4} = - check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - - BaseApps = - case systools_make:get_release(BaseRelFile, Path) of - {ok, _, NameVsnApps, _Warns} -> - lists:map(fun({_,App}) -> App end, NameVsnApps); - Other1 -> - throw(Other1) - end, + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), case systools_rc:translate_scripts(up, RUs4, TopApps, BaseApps) of - {ok, RUs} -> + {ok, RUs5} -> + + {RUs, Ws5} = fix_r15_sasl_upgrade(RUs5,Ws4,BaseNameVsns), + VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_up(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws4, [VDR| Acc]); + Opts, Ws5, [VDR| Acc]); XXX -> throw(XXX) end; @@ -294,42 +313,41 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), - - %% BaseRel = #release - - %% RUs = (release upgrade scripts) - %% - {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []), - - {BaseApps, Ws2} = + {BaseRel, BaseApps, Ws0} = case systools_make:get_release(BaseRelFile, Path) of %% %% NameVsnApps = [{{Name, Vsn}, #application}] - {ok, _, NameVsnApps, Warns} -> - %% - %% NApps = [#application] - NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), - {NApps, Warns ++ Ws1}; + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NApps = [#application] + NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), + {BR, NApps, Warns} + end; Other -> throw(Other) end, - RUs2 = RUs1, + %% BaseRel = #release + + %% RUs = (release upgrade scripts) + %% + {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws0++Ws, []), - {RUs3, Ws3} = create_add_app_scripts(TopRel, BaseRel, RUs2, Ws2), + {RUs2, Ws2} = create_add_app_scripts(TopRel, BaseRel, RUs1, Ws1), - {RUs4, Ws4} = create_remove_app_scripts(TopRel, BaseRel, RUs3, Ws3), + {RUs3, Ws3} = create_remove_app_scripts(TopRel, BaseRel, RUs2, Ws2), - {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel, - RUs4, Ws4, Opts), + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - case systools_rc:translate_scripts(dn, RUs5, BaseApps, TopApps) of + case systools_rc:translate_scripts(dn, RUs4, BaseApps, TopApps) of {ok, RUs} -> VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_dn(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws5, [VDR| Acc]); + Opts, Ws4, [VDR| Acc]); XXX -> throw(XXX) end; @@ -343,14 +361,42 @@ foreach_baserel_dn( _, _, [], _, _, Ws, Acc) -> %% check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, #release{erts_vsn = Vsn2, name = N2}, RUs, Ws, - _Opts) when Vsn1 /= Vsn2 -> - {RUs++[[restart_new_emulator]], [{erts_vsn_changed, {N1, N2}} | Ws]}; + Opts) when Vsn1 /= Vsn2 -> + %% Automatically insert a restart_new_emulator instruction when + %% erts version is changed. Also allow extra restart at the end of + %% the upgrade if restart_emulator option is given. + NewRUs = [[restart_new_emulator]|RUs], + NewWs = [{erts_vsn_changed, {{N1,Vsn1}, {N2,Vsn2}}} | Ws], + check_for_restart_emulator_opt(NewRUs, NewWs, Opts); check_for_emulator_restart(_, _, RUs, Ws, Opts) -> + check_for_restart_emulator_opt(RUs, Ws, Opts). + +check_for_restart_emulator_opt(RUs, Ws, Opts) -> case get_opt(restart_emulator, Opts) of - true -> {RUs++[[restart_new_emulator]], Ws}; + true -> {RUs++[[restart_emulator]], Ws}; _ -> {RUs, Ws} end. + +%% Special handling of the upgrade from pre R15 to post R15. In R15, +%% upgrade of the emulator was improved by moving the restart of the +%% emulator before the rest of the upgrade instructions. However, it +%% can only work if the release_handler is already upgraded to a post +%% R15 version. If not, the upgrade instructions must be backwards +%% compatible - i.e. restart_new_emulator will be the last +%% instruction, executed after all code loading, code_change etc. +fix_r15_sasl_upgrade([restart_new_emulator | RestRUs]=RUs, Ws, BaseApps) -> + case lists:keyfind(sasl,1,BaseApps) of + {sasl,Vsn} when Vsn < ?R15_SASL_VSN -> + {lists:delete(restart_emulator,RestRUs) ++ [restart_new_emulator], + [pre_R15_emulator_upgrade|Ws]}; + _ -> + {RUs,Ws} + end; +fix_r15_sasl_upgrade(RUs, Ws, _BaseApps) -> + {RUs,Ws}. + + %% collect_appup_scripts(Mode, TopApps, BaseRel, Ws, RUs) -> {NRUs, NWs} %% Mode = up | dn %% TopApps = [#application] @@ -440,13 +486,32 @@ get_script_from_appup(Mode, TopApp, BaseVsn, Ws, RUs) -> %% XXX Why is this a warning only? [{bad_vsn, {TopVsn, TopApp#application.vsn}}| Ws] end, - case lists:keysearch(BaseVsn, 1, VsnRUs) of - {value, {_, RU}} -> + case appup_search_for_version(BaseVsn, VsnRUs) of + {ok, RU} -> {RUs ++ [RU], Ws1}; - _ -> + error -> throw({error, ?MODULE, {no_relup, FName, TopApp, BaseVsn}}) end. +appup_search_for_version(BaseVsn, VsnRUs) -> + appup_search_for_version(BaseVsn, length(BaseVsn), VsnRUs). + +appup_search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) -> + {ok,RU}; +appup_search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) -> + case re:run(BaseVsn,Vsn,[unicode,{capture,first,index}]) of + {match,[{0,Size}]} -> + {ok, RU}; + _ -> + appup_search_for_version(BaseVsn,Size,VsnRUs) + end; +appup_search_for_version(BaseVsn,Size,[_|VsnRUs]) -> + appup_search_for_version(BaseVsn,Size,VsnRUs); +appup_search_for_version(_,_,[]) -> + error. + + + %% Primitives for the "lists of release names" that we upgrade from %% and to. @@ -543,7 +608,9 @@ format_error({no_relup, File, App, Vsn}) -> "in file ~p~n", [App#application.name, App#application.vsn, App#application.name, Vsn, File]); - +format_error({missing_sasl,Release}) -> + io_lib:format("No sasl application in release ~p, ~p. Can not be upgraded.", + [Release#release.name, Release#release.vsn]); format_error(Error) -> io:format("~p~n", [Error]). diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 65be134462..91a8c42484 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -36,6 +36,8 @@ MODULES= \ ERL_FILES= $(MODULES:%=%.erl) +HRL_FILES= test_lib.hrl + TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) INSTALL_PROGS= $(TARGET_FILES) @@ -84,7 +86,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR) + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR) chmod -R u+w $(RELSYSDIR) @tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index f5ceab0dc4..6942ec21ea 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -19,20 +19,33 @@ -module(installer). +-include("test_lib.hrl"). + %%-compile(export_all). -export([install_1/2]). -export([install_2/1]). -export([install_3/2]). --export([install_3a/1]). +-export([install_6a/1]). -export([install_4/1]). -export([install_5/1]). -export([install_5a/1]). -export([install_6/1]). -export([install_7/1]). +-export([install_7a/1]). -export([install_8/1]). +-export([install_8a/1]). -export([install_9/1]). -export([install_10/1]). -export([install_11/1]). +-export([install_12/1]). +-export([install_13/1]). +-export([install_14/1]). +-export([upgrade_restart_1/2]). +-export([upgrade_restart_1a/1]). +-export([upgrade_restart_2/1]). +-export([upgrade_restart_2a/1]). +-export([upgrade_restart_2b/1]). +-export([upgrade_restart_3/1]). -export([client1_1/4]). -export([client2/3]). -export([stop/1]). @@ -46,28 +59,35 @@ -define(fail(Term), exit({?MODULE, ?LINE, Term})). -define(fail_line(Line,Term), exit({?MODULE, Line, Term})). --define(check_release(Vsn,Status,Apps), - check_release(TestNode,node(),Vsn,Status,Apps,?LINE)). --define(check_release_client(Node,Vsn,Status,Apps), - check_release(TestNode,Node,Vsn,Status,Apps,?LINE)). +-define(check_release_states(States), + check_release_states(TestNode,node(),States,?LINE)). +-define(check_release_states_client(Node,States), + check_release_states(TestNode,Node,States,?LINE)). + +-define(check_release_lib(Vsn,Apps), + check_release_lib(TestNode,node(),Vsn,Apps,?LINE)). +-define(check_release_lib_client(Node,Vsn,Apps), + check_release_lib(TestNode,Node,Vsn,Apps,?LINE)). -define(check_running_app(App,Vsn), check_running_app(TestNode,node(),App,Vsn,?LINE)). -define(check_running_app_client(Node,App,Vsn), check_running_app(TestNode,Node,App,Vsn,?LINE)). +-define(check_disallowed_calls,check_disallowed_calls(TestNode,?LINE)). + install_1(TestNode,PrivDir) -> ?print([TestNode]), ?print(["install_1 start"]), + ?check_release_states([permanent]), % Unpack and install P1H {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?print(["unpack_release P1H ok"]), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?print(["install_release P1H ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ?check_running_app(a,"1.0"), X = a:a(), ?print(["X", X]), @@ -81,173 +101,351 @@ install_2(TestNode) -> ?print(["install_2 start"]), % Check that P1H is still unpacked, install it and make_permanent - ?check_release("P1H",unpacked,["a-1.0"]), - ?print(["install_2 P1H unpacked"]), + ?check_release_states([permanent,unpacked]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), ?print(["install_2 install_release ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.0"), + ok = release_handler:make_permanent("P1H"), + ?print(["install_2 make permanent P1H ok"]), + ?check_release_states([old,permanent]), ?check_running_app(a,"1.0"), - ok = release_handler:make_permanent("P1H"). + ok. % release_handler_SUITE will reboot this node now! install_3(TestNode,PrivDir) -> ?print(["install_3 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), % Unpack and install P1I {ok, "P1I"} = unpack_release(PrivDir,"rel2"), - ?print(["install_3 unpack_release P1I ok"]), - ?check_release("P1I",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,unpacked]), + ?check_release_lib("P1I",["a-1.1"]), {ok,"P1H",[{extra, gott}]} = release_handler:check_install_release("P1I"), + ?print(["install_3 check_install_release P1I ok"]), {error,_} = release_handler:check_install_release("P1J"), + ?print(["install_3 check_install_release P1J fails - ok"]), {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), - ?print(["install_3 install_release P1I ok"]), - ?check_release("P1I",current,["a-1.1"]), + ?check_release_states([old,permanent,current]), ?check_running_app(a,"1.1"), X2 = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X2), {key1, val1} = lists:keyfind(key1, 1, X2), {ok, bval} = a:b(), + ?print(["install_3 env ok"]), - % Unpack and install P2A + % Unpack P2A {ok, "P2A"} = unpack_release(PrivDir,"rel3"), - ?print(["install_3 unpack_release P2A ok"]), - ?check_release("P2A",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,current,unpacked]), + ?check_release_lib("P2A",["a-1.1"]), {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), ?print(["install_3 check_install_release P2A ok"]), - ok = release_handler:make_permanent("P1I"), - ?print(["install_3 make_permanent P1I ok"]), - ?check_release("P1I",permanent,["a-1.1"]), ok. + % release_handler_SUITE will reboot this node now! + +install_4(TestNode) -> + ?print(["install_4 start"]), -install_3a(TestNode) -> - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + %% Check that P1H is the one that is used + ?check_release_states([old,permanent,unpacked,unpacked]), + ?check_running_app(a,"1.0"), + + %% Install P2A + {continue_after_restart, "P1H", [new_emu,new_appl]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_3 P2A installed"]), + ?print(["install_4 P2A installed"]), ok. +install_5(TestNode) -> + ?print(["install_5 start"]), -install_4(TestNode) -> - ?print(["install_4 start"]), + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1H"} = init:script_id(), + + %% Check that P2A is in use. + ?check_release_states([old,permanent,unpacked,current]), + ?check_running_app(a,"1.1"), + X = a:a(), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = a:b(), + ?print(["install_5 check env ok"]), + ok. + +install_5a(TestNode) -> + ?print(["install_5a start"]), + + %% Install P1I (this will be a downgrade) + {ok, "P1I", [old_emu]} = release_handler:install_release("P1I"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_5a P1I installed"]), + ok. + +install_6(TestNode) -> + ?print(["install_6 start"]), + + %% Check that P1I is used + ?check_release_states([old,permanent,current,old]), + ?check_running_app(a,"1.1"), + + %% Make P1I permanent + ok = release_handler:make_permanent("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), + ok. + +install_6a(TestNode) -> + %% Install P2A + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_6a P2A installed"]), + ok. + +install_7(TestNode) -> + ?print(["install_7 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is in use. - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), + ?print(["install_7 check env ok"]), ok. - % release_handler_SUITE will reboot this node now! -install_5(TestNode) -> - ?print(["install_5 start"]), +install_7a(TestNode) -> + %% Install P1H (this will be a downgrade) + {ok, "P1H", [old_emu,old_appl]} = release_handler:install_release("P1H"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_7a P1H installed"]), + ok. - % Check that P1I is used - {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), +install_8(TestNode) -> + ?print(["install_8 start"]), + + %% Check that P1H is used + ?check_release_states([old,current,permanent,old]), + ?check_running_app(a,"1.0"), + {ok,"P1H",[new_emu,new_appl]} = release_handler:check_install_release("P2A"), + ?print(["install_8 check_install_release P2A ok"]), + + %% Install P1I and check that it is permanent + {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), ok. -install_5a(TestNode) -> +install_8a(TestNode) -> % Install P2A again - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_5 P2A installed"]), + ?print(["install_8a P2A installed"]), ok. -install_6(TestNode) -> - ?print(["install_6 start"]), +install_9(TestNode) -> + ?print(["install_9 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is used - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), - ok = release_handler:make_permanent("P2A"). + ?print(["install_9 check env ok"]), + ok = release_handler:make_permanent("P2A"), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), + ok. % release_handler_SUITE will reboot this node now! -install_7(TestNode) -> - ?print(["install_7 start"]), +install_10(TestNode) -> + ?print(["install_10 start"]), % Check that P2A is used - ?check_release("P2A",permanent,["a-1.1"]), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), % Install old P1H ok = release_handler:reboot_old_release("P1H"), + ?print(["install_10 reboot_old ok"]), ok. -install_8(TestNode) -> - ?print(["install_8 start"]), + +install_11(TestNode) -> + ?print(["install_11 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent,old,old]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_11 check env ok"]), %% Remove P1I and P2A and check that a-1.1 and erts-<latest> are removed ok = release_handler:remove_release("P2A"), + ?check_release_states([old,permanent,old]), ok = release_handler:remove_release("P1I"), + ?check_release_states([old,permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), true = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), {ok, Dirs} = file:list_dir(code:root_dir()), - ["erts-4.4"] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ErtsDir = "erts-"++?ertsvsn, + [ErtsDir] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ?print(["install_11 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_9(TestNode) -> - ?print(["install_9 start"]), +install_12(TestNode) -> + ?print(["install_12 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_12 check env ok"]), % Install old P1G ok = release_handler:reboot_old_release("P1G"), + ?print(["install_12 reboot_old ok"]), ok. -install_10(TestNode) -> - ?print(["install_10 start"]), +install_13(TestNode) -> + ?print(["install_13 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), - ?check_release("P1H",old,["a-1.0"]), + ?check_release_states([permanent,old]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), %% Remove P1H and check that both versions of application a is removed ok = release_handler:remove_release("P1H"), + ?check_release_states([permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), false = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), + ?print(["install_13 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_11(TestNode) -> - ?print(["install_11 start"]), +install_14(TestNode) -> + ?print(["install_14 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), + ?check_release_states([permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), ok. +%%%----------------------------------------------------------------- +%%% Ths test checks that an upgrade which both upgrades to a new +%%% emulator version, and had a restart_emulator option to +%%% systools:make_relup will be restarted twice on upgrade. +%%% (On downgrade it will happen only once.) +upgrade_restart_1(TestNode,PrivDir) -> + ?print([TestNode]), + ?print(["upgrade_restart_1 start"]), + ?check_release_states([permanent]), + + {ok, "P2B"} = unpack_release(PrivDir,"rel4"), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P2B",["a-1.1"]), + ok. + +upgrade_restart_1a(TestNode) -> + ?print(["upgrade_restart_1a start"]), + + {continue_after_restart,"P1G",[new_emu,add_appl]} = + release_handler:install_release("P2B"), + ?print(["upgrade_restart_1a P2B installed"]), + ok. + +upgrade_restart_2(TestNode) -> + ?print(["upgrade_restart_2 start"]), + + %% Check that the node has been restarted once more after the tmp release + case init:script_id() of + {"SASL-test","P2B"} -> + upgrade_restart_2a(TestNode); + {"SASL-test","__new_emulator__P1G"} -> + %% catched the node too early - give it another try + {wait,whereis(init)} + end. + +upgrade_restart_2a(TestNode) -> + ?print(["upgrade_restart_2a start"]), + + %% This time we must be there, else something is definitely wrong + {"SASL-test","P2B"} = init:script_id(), + + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.1"), + + ok = release_handler:make_permanent("P2B"), + ?check_release_states([old,permanent]), + + ok. + +upgrade_restart_2b(TestNode) -> + ?print(["upgrade_restart_2b start"]), + + {ok,"P1G",[old_emu,rm_appl]} = release_handler:install_release("P1G"), + ?print(["upgrade_restart_2b P1G installed"]), + ok. + +upgrade_restart_3(TestNode) -> + ?print(["upgrade_restart_3 start"]), + + %% Ideally we should test that the node has only been restarted + %% once... but that's not so easy. Let's just check that P1G is running. + ?check_release_states([current,permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["upgrade_restart_3 no a application found - ok"]), + + ok. + + + %%----------------------------------------------------------------- %% This test starts a client node which uses this node as master @@ -272,6 +470,8 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> Node = start_client(TestNode,client1,ClientSname), trace_disallowed_calls(Node), + ?check_release_states_client(Node,[permanent]), + %% Check env var for SASL on client node SaslEnv = rpc:call(Node, application, get_all_env, [sasl]), ?print([{client1_1,sasl_env},SaslEnv]), @@ -300,13 +500,14 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> %% as default. But it is given here in order to force hitting the %% release_handler:check_path function so it can be checked that %% it does not use file:read_file_info on the client node, see - %% trace_disallowed_calls/1 and check_disallowed_calls/0 below. + %% trace_disallowed_calls/1 and check_disallowed_calls/2 below. %% (OTP-9142) {ok, "P1H"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1HDir, "rel1.rel"), [{a,"1.0",filename:join(MasterDir,lib)}]]), - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), + ?check_release_lib_client(Node,"P1H",["a-1.0"]), ok = rpc:call(Node, release_handler, install_file, ["P1H", filename:join(P1HDir, "start.boot")]), @@ -323,13 +524,16 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), + ?check_release_states_client(Node,[permanent,current]), + ?check_running_app_client(Node,a,"1.0"), + Apps = rpc:call(Node, application, which_applications, []), {a,"A CXC 138 11","1.0"} = lists:keyfind(a, 1, Apps), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -339,17 +543,17 @@ client1_2(TestNode,PrivDir,Node) -> ?print(["client1_2 start"]), %% Check that P1H is still unpacked, install it and make_permanent - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), - ?check_release_client(Node,"P1H",current,["a-1.0"]), + ?check_release_states_client(Node,[permanent,current]), ?check_running_app_client(Node,a,"1.0"), ok = rpc:call(Node, release_handler, make_permanent, ["P1H"]), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -359,10 +563,8 @@ client1_3(TestNode,PrivDir,Node) -> ?print(["client1_3 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), - X = rpc:call(Node, a, a, []), - {key2, val2} = lists:keyfind(key2, 1, X), - {key1, val1} = lists:keyfind(key1, 1, X), + ?check_release_states_client(Node,[old,permanent]), + ?check_running_app_client(Node,a,"1.0"), %% Unpack P1I on master {ok, "P1I"} = unpack_release(PrivDir,"rel2"), @@ -374,7 +576,8 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1IDir, "rel2.rel"),[]]), - ?check_release_client(Node,"P1I",unpacked,["a-1.1"]), + ?check_release_states_client(Node,[old,permanent,unpacked]), + ?check_release_lib_client(Node,"P1I",["a-1.1"]), ok = rpc:call(Node, release_handler, install_file, ["P1I", filename:join(P1IDir, "start.boot")]), @@ -389,6 +592,7 @@ client1_3(TestNode,PrivDir,Node) -> {ok,"P1H",[{extra, gott}]} = rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X2 = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X2), @@ -404,6 +608,9 @@ client1_3(TestNode,PrivDir,Node) -> rpc:call(Node, release_handler, set_unpacked, [filename:join(P2ADir, "rel3.rel"),[]]), + ?check_release_states_client(Node,[old,permanent,current,unpacked]), + ?check_release_lib_client(Node,"P2A",["a-1.1"]), + ok = rpc:call(Node, release_handler, install_file, ["P2A", filename:join(P2ADir, "start.boot")]), ok = rpc:call(Node, release_handler, install_file, @@ -413,66 +620,136 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I", [new_emu]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + %% Reboot from P1H + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_4(TestNode,Node). + +client1_4(TestNode,Node) -> + ?print(["client1_4 start"]), + + %% check that P1H is used + ?check_release_states_client(Node,[old,permanent,unpacked,unpacked]), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {continue_after_restart, "P1H", [new_emu,new_appl]} = + rpc:call(Node, release_handler, install_release, ["P2A"]), + %% Reboots the client ! + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_5(TestNode,Node). + +client1_5(TestNode,Node) -> + ?print(["client1_5 start"]), + + %% Check that P2A is in use. + ?check_release_states_client(Node,[old,permanent,unpacked,current]), + ?check_running_app_client(Node,a,"1.1"), + X = rpc:call(Node, a, a, []), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = rpc:call(Node, a, b, []), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1I",[old_emu]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_6(TestNode,Node). + +client1_6(TestNode,Node) -> + ?print(["client1_6 start"]), + + ?check_release_states_client(Node,[old,permanent,current,old]), + ?check_running_app_client(Node,a,"1.1"), + ok = rpc:call(Node, release_handler, make_permanent, ["P1I"]), - ?check_release_client(Node,"P1I",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,old]), %% since the install_release below reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% Reboots the client ! check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_4(TestNode,Node). + client1_7(TestNode,Node). -client1_4(TestNode,Node) -> - ?print(["client1_4 start"]), +client1_7(TestNode,Node) -> + ?print(["client1_7 start"]), %% Check that P2A is in use. - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = rpc:call(Node, a, b, []), - %% Reboot from P1I - check_disallowed_calls(), - reboot(TestNode,Node), + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1H",[old_emu,old_appl]} = + rpc:call(Node, release_handler, install_release, ["P1H"]), + + check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_5(TestNode,Node). + client1_8(TestNode,Node). -client1_5(TestNode,Node) -> - ?print(["client1_5 start"]), +client1_8(TestNode,Node) -> + ?print(["client1_8 start"]), - %% Check that P1I is used - {ok, "P1I", [new_emu]} = + %% Check that P1H is used + ?check_release_states_client(Node,[old,current,permanent,old]), + ?check_running_app_client(Node,a,"1.0"), + {ok, "P1H", [new_emu,new_appl]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + {ok,"P1H",[{extra, gott}]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,old,permanent,old]), + ?check_running_app_client(Node,a,"1.1"), + + %% since the install_release below will reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install P2A again - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% We are rebooted again. check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_6(TestNode,Node). + client1_9(TestNode,Node). -client1_6(TestNode,Node) -> - ?print(["client1_6 start"]), +client1_9(TestNode,Node) -> + ?print(["client1_9 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), @@ -481,22 +758,23 @@ client1_6(TestNode,Node) -> %% Make P2A permanent ok = rpc:call(Node, release_handler, make_permanent, ["P2A"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% Reboot from P2A - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_7(TestNode,Node). + client1_10(TestNode,Node). -client1_7(TestNode,Node) -> - ?print(["client1_7 start"]), +client1_10(TestNode,Node) -> + ?print(["client1_10 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1H @@ -505,41 +783,45 @@ client1_7(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_8(TestNode,Node). + client1_11(TestNode,Node). -client1_8(TestNode,Node) -> - ?print(["client1_8 start"]), +client1_11(TestNode,Node) -> + ?print(["client1_11 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent,old,old]), + ?check_running_app_client(Node,a,"1.0"), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - %% Remove P1I and P2I from client + %% Remove P1I and P2A from client ok = rpc:call(Node, release_handler, set_removed, ["P2A"]), + ?check_release_states_client(Node,[old,permanent,old]), ok = rpc:call(Node, release_handler, set_removed, ["P1I"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), - reboot(TestNode,Node), - trace_disallowed_calls(Node), - - client1_9(TestNode,Node). - -client1_9(TestNode,Node) -> - ?print(["client1_9 start"]), - - %% Check that P2A and P1I does not exists and that PiH is permanent. + %% Check that P2A and P1I does not exists Rels = rpc:call(Node, release_handler, which_releases, []), false = lists:keysearch("P2A", 2, Rels), false = lists:keysearch("P1I", 2, Rels), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_12(TestNode,Node). + +client1_12(TestNode,Node) -> + ?print(["client1_12 start"]), + + ?check_release_states_client(Node,[old,permanent]), + %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1G @@ -548,33 +830,34 @@ client1_9(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_10(TestNode,Node). + client1_13(TestNode,Node). -client1_10(TestNode,Node) -> - ?print(["client1_10 start"]), +client1_13(TestNode,Node) -> + ?print(["client1_13 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), - ?check_release_client(Node,"P1H",old,["a-1.0"]), + ?check_release_states_client(Node,[permanent,old]), {error,client_node} = rpc:call(Node,release_handler,remove_release,["P1H"]), ok = rpc:call(Node, release_handler, set_removed, ["P1H"]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_11(TestNode,Node). + client1_14(TestNode,Node). -client1_11(TestNode,Node) -> - ?print(["client1_11 start"]), +client1_14(TestNode,Node) -> + ?print(["client1_14 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, stop_client(TestNode,Node), %% TEST IS OK !! net_kernel:monitor_nodes(false), + %% Remove releases from master ok = release_handler:remove_release("P2A"), ok = release_handler:remove_release("P1I"), ok = release_handler:remove_release("P1H"), @@ -595,9 +878,10 @@ trace_disallowed_calls(Node) -> rpc:call(Node,dbg,p,[all,call]), rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]). -check_disallowed_calls() -> +check_disallowed_calls(TestNode,Line) -> receive Trace when element(1,Trace)==trace -> + ?print_line(Line,["Disallowed function called",Trace]), exit({disallowed_function_call,Trace}) after 0 -> ok @@ -628,7 +912,7 @@ start_client_unix(TestNode,Sname,Node) -> start_client_win32(TestNode,Client,ClientSname) -> Name = atom_to_list(ClientSname) ++ "_P1G", RootDir = code:root_dir(), - ErtsBinDir = filename:join(RootDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([RootDir,"erts-"++?ertsvsn,"bin"]), {ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname, RootDir), @@ -729,8 +1013,10 @@ client2(TestNode,PrivDir,ClientSname) -> ok end, + %% Unpack P1H on master {ok, "P1H"} = unpack_release(PrivDir,"rel1"), + %% Try to set P1H unpacked on client Root = code:root_dir(), {error,{bad_masters,[Master2]}} = rpc:call(Node, release_handler, set_unpacked, @@ -755,15 +1041,17 @@ stop(Now) -> unpack_p1h(TestNode,PrivDir) -> {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), ok. permanent_p1h(TestNode) -> - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ok = release_handler:make_permanent("P1H"), - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), ok. @@ -779,24 +1067,38 @@ registered_loop(_Name) -> exit(killed) end. -check_release(TestNode,Node,Vsn,Status,Apps,Line) -> +%% Checks that the list of states for all releases (sorted on vsn) +%% equals the input States +check_release_states(TestNode,Node,States,Line) -> + case rpc:call(Node,release_handler,which_releases,[]) of + {badrpc,_}=Error -> + ?fail_line(Line,{check_release_states,Node,States,Error}); + Rels -> + ?print_line(Line,["check_release_states:", Rels]), + States = [Status || {_,_,_,Status} <- lists:keysort(2,Rels)], + ok + end. + +%% Check that the given release (Vsn) sees the correct vsn of App. +check_release_lib(TestNode,Node,Vsn,Apps,Line) -> case rpc:call(Node,release_handler,which_releases,[]) of {badrpc,_}=Error -> - ?fail_line(Line,{check_release,Node,Vsn,Status,Error}); + ?fail_line(Line,{check_release_lib,Node,Vsn,Apps,Error}); Rels -> - ?print_line(Line,["check_release:", Rels]), - {"SASL-test", Vsn, Libs, Status} = lists:keyfind(Vsn, 2, Rels), + ?print_line(Line,["check_release_lib:", Rels]), + {"SASL-test", Vsn, Libs, _Status} = lists:keyfind(Vsn, 2, Rels), true = lists:all(fun(App) -> lists:member(App,Libs) end,Apps), ok end. +%% Check that the given Vsn of App is executed check_running_app(TestNode,Node,App,Vsn,Line) -> case rpc:call(Node,application,which_applications,[]) of {badrpc,_}=Error -> ?fail_line(Line,{check_running_app,Node,App,Vsn,Error}); Apps -> ?print_line(Line,["check_running_app:", Apps]), - {App, _, Vsn} = lists:keyfind(a, 1, Apps), + {App, _, Vsn} = lists:keyfind(App, 1, Apps), ok end. diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index af2183bfff..11f8bbe4fe 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -19,6 +19,7 @@ -module(release_handler_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("test_lib.hrl"). -compile(export_all). @@ -30,6 +31,7 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. init_per_suite(Config) -> + init_priv_dir(Config), application:start(sasl), Config. @@ -58,7 +60,8 @@ cases() -> [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, otp_9395_check_old_code, otp_9395_check_and_purge, otp_9395_update_many_mods, otp_9395_rm_many_mods, - instructions, eval_appup, supervisor_which_children_timeout]. + instructions, eval_appup, supervisor_which_children_timeout, + release_handler_which_releases, install_release_syntax_check]. groups() -> [{release,[], @@ -69,6 +72,7 @@ groups() -> {release_single,[], [ upgrade, + upgrade_restart, client1, client2 ]}, @@ -82,7 +86,7 @@ groups() -> init_per_group(release, Config) -> Dog = ?t:timetrap(?default_timeout), P1gInstall = filename:join(priv_dir(Config),p1g_install), - ok = do_create_p1g(Config,P1gInstall), + ok = create_p1g(Config,P1gInstall), ok = create_p1h(Config), ?t:timetrap_cancel(Dog); @@ -95,6 +99,7 @@ init_per_group(release_single, Config) -> %% Create some more releases to upgrade to ok = create_p1i(Config), ok = create_p2a(Config), + ok = create_p2b(Config), ?t:timetrap_cancel(Dog); @@ -155,7 +160,7 @@ end_per_group(release, Config) -> {win32,_} -> delete_all_services(); _ -> ok end, - delete_release(Config), + clean_priv_dir(Config,true), ?t:timetrap_cancel(Dog), Config; end_per_group(_GroupName, Config) -> @@ -191,7 +196,10 @@ end_per_testcase(Case, Config) -> FailDir = filename:join(SaveDir,lists:concat(["failed-",Case])), ok = filelib:ensure_dir(filename:join(FailDir,"*")), - LogDirs = filelib:wildcard(filename:join([PrivDir,"*",log])), + LogDirs = + filelib:wildcard(filename:join([PrivDir,"*",log])) ++ + filelib:wildcard(filename:join([PrivDir,"*",clients, + type1,"*",log])), lists:foreach( fun(LogDir) -> @@ -236,7 +244,7 @@ break(Config) -> ?t:break(priv_dir(Config)), ok. -%% Test upgrade and downgrade of erts +%% Test upgrade and downgrade of erts and other apps on embedded node upgrade(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node ?t:format("upgrade ~p~n",[reg_print_proc]), @@ -259,54 +267,75 @@ upgrade(Conf) when is_list(Conf) -> stop_cover(TestNode), reboot_and_wait(TestNode,"install_2",[a]), - %% check that P1H is permanent, unpack and install P1I, unpack and install P2A - TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + %% check that P1H is permanent, unpack and install P1I, unpack P2A ok = rpc_inst(TestNode, install_3, [PrivDir]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_3a, []), - wait_nodes_up([{TestNode,TestNodeInit1}],"install_3",[a]), + reboot_and_wait(TestNode,"install_3",[a]), - %% check that P2A is used, reboot from P1I - ok = rpc_inst(TestNode, install_4, []), + %% check that P1H is used, install P2A + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_4",[a]), + ok = rpc_inst(TestNode, install_4, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"install_4",[a]), - %% check that P1I, reinstall P2A + %% check that P2A is used, then downgrade to P1I TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_5, []), stop_cover(TestNode), ok = rpc_inst(TestNode, install_5a, []), wait_nodes_up([{TestNode,TestNodeInit2}],"install_5",[a]), - %% check that P2A is used, make P2A permanent + %% Check that P1I is used, then make P1I permanent and install P2A + TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_6, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_6",[a]), + ok = rpc_inst(TestNode, install_6a, []), + wait_nodes_up([{TestNode,TestNodeInit3}],"install_6",[a]), - %% check that P2A is permanent, install old P1H - TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), - stop_cover(TestNode), + %% check that P2A is used, then downgrade to P1H + TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_7, []), - wait_nodes_up([{TestNode,TestNodeInit3}],"install_7",[a]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_7a, []), + wait_nodes_up([{TestNode,TestNodeInit4}],"install_7",[a]), - %% check that P1H is permanent, remove P1I and P2A + %% check that P1H is used, then install P1I and check that it is permanent + %% then reinstall P2A + TestNodeInit5 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_8, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_8",[a]), + ok = rpc_inst(TestNode, install_8a, []), + wait_nodes_up([{TestNode,TestNodeInit5}],"install_8",[a]), + + %% check that P2A is used, make P2A permanent + ok = rpc_inst(TestNode, install_9, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_9",[a]), + + %% check that P2A is permanent, reboot to old P1H + TestNodeInit6 = rpc:call(TestNode,erlang,whereis,[init]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_10, []), + wait_nodes_up([{TestNode,TestNodeInit6}],"install_10",[a]), + + %% check that P1H is permanent, remove P1I and P2A + ok = rpc_inst(TestNode, install_11, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_11",[a]), %% check that P1H is permanent, reboot old P1G - TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), + TestNodeInit7 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_9, []), - wait_nodes_up([{TestNode,TestNodeInit4}],"install_9"), + ok = rpc_inst(TestNode, install_12, []), + wait_nodes_up([{TestNode,TestNodeInit7}],"install_12"), %% check that P1G is permanent, remove P1H - ok = rpc_inst(TestNode, install_10, []), + ok = rpc_inst(TestNode, install_13, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_10"), + reboot_and_wait(TestNode,"install_13"), %% check that P1G is permanent - ok = rpc_inst(TestNode, install_11, []), + ok = rpc_inst(TestNode, install_14, []), ok. @@ -323,6 +352,54 @@ reboot_and_wait(Node,Tag,Apps) -> wait_nodes_up([{Node,InitPid}],Tag,Apps). +%% Test upgrade and downgrade of erts in combination with the +%% restart_emulator option to systools:make_relup. For upgrade, this +%% should cause one restart before the upgrade code, and one +%% after. For downgrade, there will be one restart only - at the end. +upgrade_restart(Conf) when is_list(Conf) -> + reg_print_proc(), %% starts a printer process on test_server node + ?t:format("upgrade_restart ~p~n",[reg_print_proc]), + PrivDir = priv_dir(Conf), + Sname = tc_sname(Conf), % nodename for use in this testcase + + %% Copy the P1G release to a directory for use in this testcase + ok = copy_installed(Conf,p1g_install,[Sname]), + + %% start the test node + [TestNode] = start_nodes(Conf,[Sname],"upgrade_restart start"), + + %% unpack and install P2B + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + ok = rpc_inst(TestNode, upgrade_restart_1, [PrivDir]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_1a, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"upgrade_restart_1",[a]), + + %% install P1G + case rpc_inst(TestNode, upgrade_restart_2, []) of + ok -> + ok; + {wait,TestNodeInit2a} -> + %% We catched the node too early - it was supposed to + %% restart twice, so let's wait for one more restart. + wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]), + ok = rpc_inst(TestNode, upgrade_restart_2a, []) + end, + TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_2b, []), + wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2b",[]), + + %% Check that P1G is going again + ok = rpc_inst(TestNode, upgrade_restart_3, []), + + ok. + +upgrade_restart(cleanup,Config) -> + TestNode = tc_full_node_name(Config), + ok = stop_nodes([TestNode]). + + %% Test upgrade and downgrade of erts, diskless client1(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node @@ -542,9 +619,51 @@ supervisor_which_children_timeout(Conf) -> ok. -supervisor_which_children_timeout(cleanup, Conf) -> +supervisor_which_children_timeout(cleanup, _Conf) -> stop_node(node_name(supervisor_which_children_timeout)). + +%% Test that check_install_release will fail for illegal relup +%% instructions, even after point of no return. +install_release_syntax_check(Conf) when is_list(Conf) -> + + S1 = [point_of_no_return, illegal_instruction], + {error,{illegal_instruction_after_point_of_no_return,illegal_instruction}} = + release_handler_1:check_script(S1,[]), + + S2 = [point_of_no_return,restart_new_emulator], + {error,{illegal_instruction_after_point_of_no_return,restart_new_emulator}} = + release_handler_1:check_script(S2,[]), + + ok. + + +%%----------------------------------------------------------------- +%% release_handler:which_releases/0 and 1 test +%%----------------------------------------------------------------- +release_handler_which_releases(Conf) -> + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"release_handler_which_releases"), + DataDir = ?config(data_dir,Conf), + LibDir = filename:join([DataDir,release_handler_timeouts]), + + Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + + {ok, Node} = t_start_node(release_handler_which_releases, Rel1, []), + Releases0 = rpc:call(Node, release_handler, which_releases, []), + Releases1 = rpc:call(Node, release_handler, which_releases, [permanent]), + Releases2 = rpc:call(Node, release_handler, which_releases, [old]), + + 1 = length(Releases0), + 1 = length(Releases1), + 0 = length(Releases2), + + ?t:format("release_handler:which_releases/0: ~p~n", [Releases0]), + ?t:format("release_handler:which_releases/1: ~p~n", [Releases1]), + ?t:format("release_handler:which_releases/1: ~p~n", [Releases2]), + + ok. + %%----------------------------------------------------------------- %% Ticket: OTP-2740 %% Slogan: vsn not numeric doesn't work so good in release_handling @@ -1147,11 +1266,10 @@ target_system(Conf) when is_list(Conf) -> %% Create the .rel file - ErtsVsn = erlang:system_info(version), RelName = filename:join(TargetCreateDir,"ts-1.0"), RelFile = RelName++".rel", RelVsn = "R1A", - create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,[{a, "1.0"}]), + create_rel_file(RelFile,RelName,RelVsn,current,[{a, "1.0"}]), %% Build the target_system module ExamplesEbin = filename:join([code:lib_dir(sasl),examples,ebin]), @@ -1179,11 +1297,12 @@ target_system(Conf) when is_list(Conf) -> code:del_path(TSPath), %% Check that all files exist in installation - true = filelib:is_dir(filename:join(TargetInstallDir,"erts-"++ErtsVsn)), + ErtsDir = app_dir(erts,current), + true = filelib:is_dir(filename:join(TargetInstallDir,ErtsDir)), LibDir = filename:join(TargetInstallDir,lib), - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), + KernelVsn = vsn(kernel,current), + StdlibVsn = vsn(stdlib,current), + SaslVsn = vsn(sasl,current), true = filelib:is_dir(filename:join(LibDir,"kernel-"++KernelVsn)), true = filelib:is_dir(filename:join(LibDir,"stdlib-"++StdlibVsn)), true = filelib:is_dir(filename:join(LibDir,"sasl-"++SaslVsn)), @@ -1205,6 +1324,7 @@ target_system(Conf) when is_list(Conf) -> true = filelib:is_regular(filename:join(BinDir,to_erl)), %% Check content of files + ErtsVsn = vsn(erts,current), {ok,SED} = file:read_file(filename:join(RelDir,"start_erl.data")), [ErtsVsn,RelVsn] = string:tokens(binary_to_list(SED),"\s\n"), ok. @@ -1456,7 +1576,7 @@ copy_client(Conf,Master,Sname,Client) -> ok. -delete_release(Conf) -> +clean_priv_dir(Conf,Save) -> PrivDir = priv_dir(Conf), {ok, OrigWd} = file:get_cwd(), @@ -1466,7 +1586,7 @@ delete_release(Conf) -> {ok, Dirs} = file:list_dir(PrivDir), ?t:format("======== deleting ~p~n",[Dirs]), - ok = delete_release_os(Dirs--["save"]), + ok = clean_dirs_os(Dirs,Save), {ok,Remaining} = file:list_dir(PrivDir), ?t:format("======== remaining ~p~n",[Remaining]), @@ -1474,7 +1594,7 @@ delete_release(Conf) -> [] -> ok; _ -> - delete_release_os(Remaining), + clean_dirs_os(Remaining,Save), Remaining2 = file:list_dir(PrivDir), ?t:format("======== remaining after second try ~p~n",[Remaining2]) end, @@ -1483,22 +1603,22 @@ delete_release(Conf) -> ok. -delete_release_os(Dirs) -> +clean_dirs_os(Dirs,Save) -> case os:type() of {unix, _} -> - delete_release_unix(Dirs); + clean_dirs_unix(Dirs,Save); {win32, _} -> - delete_release_win32(Dirs); + clean_dirs_win32(Dirs,Save); Os -> test_server:fail({error, {not_yet_implemented_os, Os}}) end. -delete_release_unix([]) -> +clean_dirs_unix([],_) -> ok; -delete_release_unix(["save"|Dirs]) -> - delete_release_unix(Dirs); -delete_release_unix([Dir|Dirs]) -> +clean_dirs_unix(["save"|Dirs],Save) when Save -> + clean_dirs_unix(Dirs,Save); +clean_dirs_unix([Dir|Dirs],Save) -> Rm = string:concat("rm -rf ", Dir), ?t:format("============== COMMAND ~p~n",[Rm]), case file:list_dir(Dir) of @@ -1515,13 +1635,13 @@ delete_release_unix([Dir|Dirs]) -> ?t:format("------- ls -al ~p~n",[os:cmd("ls -al " ++ Dir)]) end, - delete_release_unix(Dirs). + clean_dirs_unix(Dirs,Save). -delete_release_win32([]) -> +clean_dirs_win32([],_) -> ok; -delete_release_win32(["save"|Dirs]) -> - delete_release_win32(Dirs); -delete_release_win32([Dir|Dirs]) -> +clean_dirs_win32(["save"|Dirs],Save) when Save -> + clean_dirs_win32(Dirs,Save); +clean_dirs_win32([Dir|Dirs],Save) -> Rm = case filelib:is_dir(Dir) of true -> @@ -1531,7 +1651,7 @@ delete_release_win32([Dir|Dirs]) -> end, ?t:format("============== COMMAND ~p~n",[Rm]), [] = os:cmd(Rm), - delete_release_win32(Dirs). + clean_dirs_win32(Dirs,Save). node_name(Sname) when is_atom(Sname) -> @@ -1657,9 +1777,17 @@ priv_dir(Conf) -> %% filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash %% Due to problem with long paths on windows => creating a new %% priv_dir under data_dir + filename:absname(filename:join(?config(data_dir, Conf),priv_dir)). + +init_priv_dir(Conf) -> Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)), - filelib:ensure_dir(filename:join(Dir,"*")), - Dir. + case filelib:is_dir(Dir) of + true -> + clean_priv_dir(Conf,false); + false -> + ok + end, + filelib:ensure_dir(filename:join(Dir,"*")). latest_version(Dir) -> List = filelib:wildcard(Dir ++ "*"), @@ -1694,14 +1822,22 @@ stop_print_proc() -> %% Create the first target release, vsn P1G. This release is used for %% all test cases in {group,release} -create_p1g(Conf,Sname) -> - do_create_p1g(Conf,filename:join(priv_dir(Conf),Sname)). - -do_create_p1g(Conf,TargetDir) -> - PrivDir = priv_dir(Conf), +create_p1g(Conf,TargetDir) -> DataDir = ?config(data_dir,Conf), - ErtsVsn = "4.4", - ErtsDir = "erts-"++ErtsVsn, + PrivDir = priv_dir(Conf), + ErtsDir = app_dir(erts,old), + KernelDir = app_dir(kernel,old), + StdlibDir = app_dir(stdlib,old), + + %% Fake earlier version of kernel and stdlib + SystemLib = system_lib(PrivDir), + ok = filelib:ensure_dir(filename:join(SystemLib,"*")), + KernelLib = code:lib_dir(kernel), + StdlibLib = code:lib_dir(stdlib), + ok = copy_tree(Conf,KernelLib,KernelDir,SystemLib), + ok = copy_tree(Conf,StdlibLib,StdlibDir,SystemLib), + fix_version(SystemLib,kernel), + fix_version(SystemLib,stdlib), %% Create dirs BinDir = filename:join(TargetDir,bin), @@ -1745,17 +1881,15 @@ do_create_p1g(Conf,TargetDir) -> RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - TarFile = create_basic_release(Conf, RelFile, RelVsn, {ErtsVsn,false}, - LibPath, [], [], [], []), + TarFile = create_basic_release(Conf,RelFile,RelVsn,{old,false}), %% Extract tar file in target directory (i.e. same directory as erts etc.) ok = erl_tar:extract(TarFile, [{cwd, TargetDir}, compressed]), %% Create start_erl.data StartErlDataFile = filename:join([ReleasesDir, "start_erl.data"]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), + StartErlData = io_lib:fwrite("~s ~s~n", [vsn(erts,old), RelVsn]), ok = file:write_file(StartErlDataFile, StartErlData), %% Create RELEASES @@ -1763,60 +1897,98 @@ do_create_p1g(Conf,TargetDir) -> ok. +fix_version(SystemLib,App) -> + FromVsn = vsn(App,current), + ToVsn = vsn(App,old), + Rootname = filename:join([SystemLib,app_dir(App,old),ebin,atom_to_list(App)]), + + AppFile = Rootname ++ ".app", + {ok,OrigApp} = file:read_file(AppFile), + ok = file:write_file(AppFile,re:replace(OrigApp,FromVsn,ToVsn, + [{return,binary}])), + AppupFile = Rootname ++ ".appup", + {ok,OrigAppup} = file:read_file(AppupFile), + ok = file:write_file(AppupFile,re:replace(OrigAppup,FromVsn,ToVsn, + [{return,binary}])). + + %% Create version P1H - which is P1G + a-1.0 %% Must have run create_p1g first!! create_p1h(Conf) -> - create_upgrade_release(Conf,"rel1","P1H",{"4.4",false},[{a,"1.0"}], - [{a,[{key2,val2}]}],{"rel0",[new_appl]}). + create_upgrade_release(Conf,"rel1","P1H",{old,false},[{a,"1.0"}], + [{a,[{key2,val2}]}],[{"rel0",[new_appl]}]). %% Create version P1I - which is P1H, but with application a upgraded to a-1.1 %% Must have run create_p1h first!! create_p1i(Conf) -> - create_upgrade_release(Conf,"rel2","P1I",{"4.4",false},[{a,"1.1"}], + create_upgrade_release(Conf,"rel2","P1I",{old,false},[{a,"1.1"}], [{a,[{key2,newval2}]}], - {"rel1",[{extra,gott}]}). + [{"rel1",[{extra,gott}]}]). %% Create version P2A - which is P1I, but with erts-<latest> %% Must have run create_p1i first!! create_p2a(Conf) -> - ErtsVsn = erlang:system_info(version), - create_upgrade_release(Conf,"rel3","P2A",{ErtsVsn,code:root_dir()}, + create_upgrade_release(Conf,"rel3","P2A",{current,code:root_dir()}, + [{a,"1.1"}],[{a,[{key2,newval2}]}], + [{"rel1",[new_emu,new_appl]},{"rel2",[new_emu]}], + [{"rel1",[old_emu,old_appl]},{"rel2",[old_emu]}]). + +%% Create version P2B - which is P2A, but with relup containing an +%% extra reboot. +%% Can be upgraded to from P1G - so must have run create_p1g first!! +create_p2b(Conf) -> + create_upgrade_release(Conf,"rel4","P2B",{current,code:root_dir()}, [{a,"1.1"}],[{a,[{key2,newval2}]}], - {"rel2",[new_emu]}). + [{"rel0",[new_emu,add_appl]}], + [{"rel0",[old_emu,rm_appl]}], + [restart_emulator]). %% Create a release tar package which can be installed on top of P1G -create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) -> +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom0,DownTo0,RelupOpts) -> PrivDir = priv_dir(Conf), - DataDir = ?config(data_dir,Conf), - RelDir = filename:join(PrivDir,RelName), RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr}], + UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr} || + {UpFromName,Descr} <- UpFrom0], + DownTo = [{filename:join([PrivDir,DownToName,DownToName]),Descr} || + {DownToName,Descr} <- DownTo0], - create_basic_release(Conf, RelFile, RelVsn, Erts, LibPath, - Apps, Config, UpFrom, []), + create_basic_release(Conf,RelFile,RelVsn,Erts,Apps,Config, + UpFrom,DownTo,RelupOpts), ok. %% Create .rel, .script, .boot, sys.config and tar -create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) -> +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir}) -> + create_basic_release(Conf, RelFile,RelVsn,{Erts,ErtsDir},[],[],[],[],[]). +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir},ExtraApps,Config,UpFrom,DownTo,RelupOpts) -> + DataDir = ?config(data_dir,Conf), + PrivDir = priv_dir(Conf), + SystemLib = system_lib(PrivDir), + LibPath = [filename:join([SystemLib,"*",ebin]), + filename:join([DataDir,lib,"*",ebin])], + RelDir = filename:dirname(RelFile), RelFileName = filename:rootname(RelFile), %% Create .rel file - create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps), + create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps), %% Generate .script and .boot ok = systools:make_script(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir}]), %% Generate relup - ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,[LibPath]}, - {outdir,RelDir}]), + ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,LibPath}, + {outdir,RelDir} | + RelupOpts]), %% Create sys.config ok = write_term_file(filename:join(RelDir,"sys.config"),Config), @@ -1824,7 +1996,7 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co %% Create tar file (i.e. collect all lib/app-*/* and system files) ok = systools:make_tar(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir} | case ErtsDir of false -> []; @@ -1841,18 +2013,19 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co TarFileName. %% Create a .rel file -create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) -> - create_rel_file(RelFile,"SASL-test",RelVsn,ErtsVsn, +create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps) -> + create_rel_file(RelFile,"SASL-test",RelVsn,Erts, [{installer,"1.0"}|ExtraApps]). -create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,ExtraApps) -> - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), +create_rel_file(RelFile,RelName,RelVsn,Erts,ExtraApps) -> + ErtsVsn = vsn(erts,Erts), + KernelVsn = vsn(kernel,Erts), + StdlibVsn = vsn(stdlib,Erts), + SaslVsn = vsn(sasl,current), application:load(tools), - {ok,ToolsVsn} = application:get_key(tools,vsn), + ToolsVsn = vsn(tools,current), application:load(runtime_tools), - {ok,RuntimeToolsVsn} = application:get_key(runtime_tools,vsn), + RuntimeToolsVsn = vsn(runtime_tools,current), RelFileContent = {release, {RelName, RelVsn}, @@ -2033,7 +2206,7 @@ start_node_unix(Sname,NodeDir) -> start_node_win32(Sname,NodeDir) -> Name = atom_to_list(Sname) ++ "_P1G", - ErtsBinDir = filename:join(NodeDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([NodeDir,app_dir(erts,old),"bin"]), StartErlArgs = rh_test_lib:get_start_erl_args(NodeDir), ServiceArgs = rh_test_lib:get_service_args(NodeDir, Sname, StartErlArgs), @@ -2158,7 +2331,6 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> RelDir = filename:join(Dir,"rel_" ++ RelVsn), Rel = filename:join([RelDir,"rel_" ++ RelVsn]), ok = filelib:ensure_dir(Rel), - ErtsVsn = erlang:system_info(version), {Apps,Paths} = lists:foldl(fun({App,Vsn,Lib},{As,Ps}) -> @@ -2168,7 +2340,7 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> {[],[]}, AppDirs), - create_rel_file(Rel++".rel",RelName,RelVsn,ErtsVsn,Apps), + create_rel_file(Rel++".rel",RelName,RelVsn,current,Apps), %% Generate boot scripts ok = systools:make_script(Rel,[local, @@ -2217,3 +2389,16 @@ modify_tar_win32(Conf, TarFileName) -> [ok = erl_tar:add(T,filename:join(TmpDir,F),F,[]) || F <- Fs], ok = erl_tar:close(T), ok. + +app_dir(App,Vsn) -> + atom_to_list(App) ++ "-" ++ vsn(App,Vsn). +vsn(erts,old) -> ?ertsvsn; +vsn(kernel,old) -> ?kernelvsn; +vsn(stdlib,old) -> ?stdlibvsn; +vsn(erts,current) -> erlang:system_info(version); +vsn(App,current) -> + {ok,Vsn} = application:get_key(App,vsn), + Vsn. + +system_lib(PrivDir) -> + filename:join(PrivDir,"system_lib"). diff --git a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat index ede1ad4ff3..ede1ad4ff3 100755..100644 --- a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat +++ b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup index 05db4cb541..6ef67b869e 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup @@ -1,3 +1,3 @@ {"1.1", [{"1.0",[{update,a,{advanced,extra_par}}]}], - []}. + [{"1.0",[{update,a,{advanced,extra_par}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl index c082ad5339..1050e53f35 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl @@ -51,4 +51,6 @@ terminate(_Reason, _State) -> ok. code_change(1, Extra, State) -> - {ok, {state, bval}}. + {ok, {state, bval}}; +code_change({down,1},Extra,State) -> + {ok, state}. diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 454095db6a..195324daa0 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -30,10 +30,11 @@ % Test cases must be exported. -export([app_test/1, + appup_test/1, log_mf_h_env/1]). all() -> - [app_test, log_mf_h_env]. + [app_test, appup_test, log_mf_h_env]. groups() -> []. @@ -57,6 +58,102 @@ app_test(Config) when is_list(Config) -> ?line ?t:app_test(sasl, allow), ok. +%% Test that appup allows upgrade from/downgrade to a maximum of two +%% major releases back. +appup_test(_Config) -> + application:load(sasl), + {sasl,_,SaslVsn} = lists:keyfind(sasl,1,application:loaded_applications()), + Ebin = filename:join(code:lib_dir(sasl),ebin), + {ok,[{SaslVsn,UpFrom,DownTo}=Appup]} = + file:consult(filename:join(Ebin,"sasl.appup")), + ct:log("~p~n",[Appup]), + ?line {OkVsns,NokVsns} = create_test_vsns(SaslVsn), + ?line check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), + ?line check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + ?line check_appup(NokVsns,UpFrom,error), + ?line check_appup(NokVsns,DownTo,error), + ok. + + +%% For sasl, the versions up to R14B03 were not according to the rule +%% used for other core applications - i.e. to change the second number +%% at major releases, the third at maintenance releases and the fourth +%% for patches - therefore test versions up to and including R16 are +%% hardcoded. +%% (All versions below are not necessarily existing.) +-define(r12_vsns,["2.1.5"]). +-define(r13_vsns,["2.1.6","2.1.7.1","2.1.9","2.1.9.1.2"]). +-define(r14_vsns,["2.1.9.2","2.1.9.2.20","2.1.9.4","2.1.10"]). +-define(r15_major,"2.2"). +-define(r16_major,"2.3"). +-define(r17_major,"2.4"). +create_test_vsns(?r15_major ++ Rest) -> + R15Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r15_major]; + _ -> [?r15_major,?r15_major++".1"] + end, + OkVsns = ?r13_vsns ++ ?r14_vsns ++ R15Vsns, + NokVsns = ?r12_vsns ++ [?r15_major++",1", ?r16_major], + {OkVsns,NokVsns}; +create_test_vsns(?r16_major ++ Rest) -> + R16Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r16_major]; + _ -> [?r16_major,?r16_major++".1"] + end, + OkVsns = ?r14_vsns ++ [?r15_major, ?r15_major ++ ".1.4"] ++ R16Vsns, + NokVsns = ?r13_vsns ++ [?r16_major++",1", ?r17_major], + {OkVsns,NokVsns}; +%% Normal erts case - i.e. for versions that comply to the erts standard +create_test_vsns(Current) -> + [XStr,YStr|Rest] = string:tokens(Current,"."), + X = list_to_integer(XStr), + Y = list_to_integer(YStr), + SecondMajor = vsn(X,Y-2), + SecondMinor = SecondMajor ++ ".1.3", + FirstMajor = vsn(X,Y-1), + FirstMinor = FirstMajor ++ ".57", + ThisMajor = vsn(X,Y), + This = + case Rest of + [] -> + []; + ["1"] -> + [ThisMajor]; + _ -> + ThisMinor = ThisMajor ++ ".1", + [ThisMajor,ThisMinor] + end, + OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], + + ThirdMajor = vsn(X,Y-3), + ThirdMinor = ThirdMajor ++ ".10.12", + Illegal = ThisMajor ++ ",1", + Newer1Major = vsn(X,Y+1), + Newer1Minor = Newer1Major ++ ".1", + Newer2Major = ThisMajor ++ "1", + NokVsns = [ThirdMajor,ThirdMinor, + Illegal, + Newer1Major,Newer1Minor, + Newer2Major], + {OkVsns,NokVsns}. + +vsn(X,Y) -> + integer_to_list(X) ++ "." ++ integer_to_list(Y). + +check_appup([Vsn|Vsns],Instrs,Expected) -> + case systools_relup:appup_search_for_version(Vsn, Instrs) of + Expected -> check_appup(Vsns,Instrs,Expected); + Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other}) + end; +check_appup([],_,_) -> + ok. + + + %% OTP-9185 - fail sasl start if some but not all log_mf_h env vars %% are given. log_mf_h_env(Config) -> diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index e352247d44..892c4994e8 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -41,7 +41,7 @@ -export([all/0,suite/0,groups/0,init_per_group/2,end_per_group/2]). -export([ script_options/1, normal_script/1, no_mod_vsn_script/1, - wildcard_script/1, variable_script/1, + wildcard_script/1, variable_script/1, no_sasl_script/1, abnormal_script/1, src_tests_script/1, crazy_script/1, warn_shadow_script/1, included_script/1, included_override_script/1, @@ -49,10 +49,11 @@ -export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, src_tests_tar/1, shadow_tar/1, var_tar/1, exref_tar/1, link_tar/1, otp_9507/1]). --export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1, - bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]). --export([ - otp_6226/1]). +-export([ normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1, + no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, + regexp_relup/1, otp_3065/1]). +-export([otp_6226/1]). +-export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). -export([init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). @@ -67,15 +68,15 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. all() -> - [{group, script}, {group, tar}, {group, relup}, + [{group, script}, {group, tar}, {group, relup}, {group, hybrid}, {group, tickets}]. groups() -> [{script, [], [script_options, normal_script, no_mod_vsn_script, wildcard_script, variable_script, abnormal_script, - src_tests_script, crazy_script, warn_shadow_script, - included_script, included_override_script, + no_sasl_script, src_tests_script, crazy_script, + warn_shadow_script, included_script, included_override_script, included_fail_script, included_bug_script, exref_script, otp_3065]}, {tar, [], @@ -83,8 +84,10 @@ groups() -> src_tests_tar, shadow_tar, var_tar, exref_tar, link_tar, otp_9507]}, {relup, [], - [normal_relup, abnormal_relup, no_appup_relup, - bad_appup_relup, app_start_type_relup]}, + [normal_relup, restart_relup, abnormal_relup, no_sasl_relup, + no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup + ]}, + {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, {tickets, [], [otp_6226]}]. init_per_group(_GroupName, Config) -> @@ -388,6 +391,32 @@ abnormal_script(Config) when is_list(Config) -> %% make_script %% +no_sasl_script(suite) -> []; +no_sasl_script(doc) -> + ["Create script without sasl appl. Check warning."]; +no_sasl_script(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir, LatestName} = create_script(latest1_no_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(LatestDir), + + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(LatestName,[{path, P},silent]), + + ?line ok = file:set_cwd(OldDir), + ok. + + +%% make_script +%% src_tests_script(suite) -> []; src_tests_script(doc) -> ["Do not check date of object file or that source code can be found."]; @@ -1106,15 +1135,17 @@ otp_9507(Config) when is_list(Config) -> RelName = fname([LatestDir,LatestName]), ?line P1 = ["./ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]), ?line ok = systools:make_tar(RelName, [{path, P1}]), ?line Content1 = tar_contents(RelName), ?line P2 = ["ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], %% Tickets solves the following line - it used to fail with %% {function_clause,[{filename,join,[[]]},...} @@ -1148,18 +1179,11 @@ normal_relup(Config) when is_list(Config) -> ?line LibDir = [fname([DataDir, d_normal, lib])], ?line P = [fname([LibDir, '*', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), - %% OTP-2561: Check that the option 'restart_emulator' generates a - %% "restart_new_emulator" instruction. - ?line {ok, _ , _, []} = - systools:make_relup(LatestName, [LatestName1], [LatestName1], - [{path, P},restart_emulator,silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line ok = check_restart_emulator(), - %% This is the ultra normal case ?line ok = systools:make_relup(LatestName, [LatestName1], [LatestName1], [{path, P}]), @@ -1188,7 +1212,7 @@ normal_relup(Config) when is_list(Config) -> ?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}]), ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), - ?line {ok, _, _, [{erts_vsn_changed, _}]} = + ?line {ok, _, _, [pre_R15_emulator_upgrade,{erts_vsn_changed, _}]} = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}, silent]), ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), @@ -1200,6 +1224,91 @@ normal_relup(Config) when is_list(Config) -> ok. +restart_relup(suite) -> []; +restart_relup(doc) -> + ["Test relup which includes emulator restart"]; +restart_relup(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir,LatestName} = create_script(latest0,Config), + ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), + ?line {_LatestDir0CurrErts,LatestName0CurrErts} = + create_script(latest0_current_erts,Config), + ?line {_CurrentAllDir,CurrentAllName} = create_script(current_all,Config), + ?line {_CurrentAllFutErtsDir,CurrentAllFutErtsName} = + create_script(current_all_future_erts,Config), + ?line {_CurrentAllFutSaslDir,CurrentAllFutSaslName} = + create_script(current_all_future_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin]), + fname([DataDir, lib, 'sasl-9.9', ebin])], + + ?line ok = file:set_cwd(LatestDir), + + %% OTP-2561: Check that the option 'restart_emulator' generates a + %% "restart_emulator" instruction. + ?line {ok, _ , _, []} = + systools:make_relup(LatestName, [LatestName1], [LatestName1], + [{path, P},restart_emulator,silent]), + ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ?line ok = check_restart_emulator(), + + + %% Pre-R15 to Post-R15 upgrade + ?line {ok, _ , _, Ws} = + systools:make_relup(LatestName0CurrErts, + [LatestName1], + [LatestName1], + [{path, P},silent]), + ?line ok = check_relup([{db,"2.1"}], [{db, "1.0"}]), + ?line ok = check_pre_to_post_r15_restart_emulator(), + ?line ok = check_pre_to_post_r15_warnings(Ws), + + + %% Check that new sasl version generates a restart_new_emulator + %% instruction + ?line {ok, _ , _, []} = + systools:make_relup(CurrentAllFutSaslName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, if FromSaslVsn >= R15SaslVsn + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, and can be combined with restart_emulator opt. + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},restart_emulator,silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator(), + ?line ok = check_restart_emulator_diff_coreapp(), + + ?line ok = file:set_cwd(OldDir), + ok. + + %% This test fails if wrong version numbers are seen in the relup file %% or if any application is missing. This was triggered by OTP-1360. check_relup(UpVsnL, DnVsnL) -> @@ -1216,10 +1325,40 @@ check_relup(UpVsnL, DnVsnL) -> [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Dn]), ok. +check_relup_up_only(UpVsnL) -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + [] = foldl(fun(X, Acc) -> + true = lists:member(X, Acc), + lists:delete(X, Acc) end, + UpVsnL, + [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Up]), + ok. + check_restart_emulator() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + restart_emulator = lists:last(Up), + restart_emulator = lists:last(Dn), + ok. + +check_restart_emulator_up_only() -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + restart_emulator = lists:last(Up), + ok. + +check_restart_emulator_diff_coreapp() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + [restart_new_emulator|_] = Up, + restart_emulator = lists:last(Dn), + ok. + +check_pre_to_post_r15_restart_emulator() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), restart_new_emulator = lists:last(Up), - restart_new_emulator = lists:last(Dn), + restart_emulator = lists:last(Dn), + ok. + +check_pre_to_post_r15_warnings(Ws) -> + true = lists:member(pre_R15_emulator_upgrade,Ws), ok. %% make_relup @@ -1235,13 +1374,14 @@ no_appup_relup(Config) when is_list(Config) -> ?line {_LatestDir1,LatestName1} = create_script(latest_small1,Config), ?line DataDir = filename:absname(?copydir), - ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], ?line ok = file:set_cwd(LatestDir), %% Check that appup might be missing + ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = systools:make_relup(LatestName, [LatestName], [], [{path, P1}]), ?line {ok,_, _, []} = @@ -1249,22 +1389,29 @@ no_appup_relup(Config) when is_list(Config) -> [silent, {path, P1}]), %% Check that appup might NOT be missing when we need it + ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line error = - systools:make_relup(LatestName, [LatestName0], [], [{path, P1}]), + systools:make_relup(LatestName, [LatestName0], [], [{path, P2}]), ?line {error,_,{file_problem, {_,{error,{open,_,_}}}}} = systools:make_relup(LatestName, [], [LatestName0], - [silent, {path, P1}]), + [silent, {path, P2}]), %% Check that appups missing vsn traps - ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + ?line P3 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-500.18.7', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line error = - systools:make_relup(LatestName0, [LatestName1], [], [{path, P2}]), + systools:make_relup(LatestName0, [LatestName1], [], [{path, P3}]), ?line {error,_,{no_relup, _, _, _}} = systools:make_relup(LatestName0, [], [LatestName1], - [silent, {path, P2}]), + [silent, {path, P3}]), ?line ok = file:set_cwd(OldDir), ok. @@ -1282,8 +1429,10 @@ bad_appup_relup(Config) when is_list(Config) -> ?line DataDir = filename:absname(?copydir), ?line N2 = [fname([DataDir, d_bad_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_bad_appup, lib, 'fe-2.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1313,7 +1462,8 @@ abnormal_relup(Config) when is_list(Config) -> ?line P = [fname([DataDir, d_bad_app_vsn, lib, 'db-2.1', ebin]), fname([DataDir, d_bad_app_vsn, lib, 'fe-3.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1329,6 +1479,37 @@ abnormal_relup(Config) when is_list(Config) -> ok. +%% make_relup +%% +no_sasl_relup(suite) -> []; +no_sasl_relup(doc) -> + ["Check relup can not be created is sasl is not in rel file"]; +no_sasl_relup(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config), + ?line {_Dir2,Name2} = create_script(latest1,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line error = systools:make_relup(Name2, [Name1], [Name1], [{path, P}]), + ?line R1 = systools:make_relup(Name2, [Name1], [Name1],[silent, {path, P}]), + ?line {error,systools_relup,{missing_sasl,_}} = R1, + + ?line error = systools:make_relup(Name1, [Name2], [Name2], [{path, P}]), + ?line R2 = systools:make_relup(Name1, [Name2], [Name2],[silent, {path, P}]), + ?line {error,systools_relup,{missing_sasl,_}} = R2, + + ?line ok = file:set_cwd(OldDir), + ok. + + %% Check that application start type is used in relup app_start_type_relup(suite) -> []; @@ -1342,35 +1523,243 @@ app_start_type_relup(Config) when is_list(Config) -> ?line Release2 = filename:join(Dir2,Name2), ?line {ok, Release2Relup, systools_relup, []} = systools:make_relup(Release2, [Release1], [Release1], [{outdir, PrivDir}, silent]), - ?line {"2", [{"1",[], UpInstructions}], [{"1",[], DownInstructions}]} = Release2Relup, + ?line {"LATEST_APP_START_TYPE2", + [{"LATEST_APP_START_TYPE1",[], UpInstructions}], + [{"LATEST_APP_START_TYPE1",[], DownInstructions}]} = Release2Relup, %% ?t:format("Up: ~p",[UpInstructions]), %% ?t:format("Dn: ~p",[DownInstructions]), ?line [{load_object_code, {mnesia, _, _}}, - {load_object_code, {sasl, _, _}}, + {load_object_code, {runtime_tools, _, _}}, {load_object_code, {webtool, _, _}}, {load_object_code, {snmp, _, _}}, {load_object_code, {xmerl, _, _}}, point_of_no_return | UpInstructionsT] = UpInstructions, ?line true = lists:member({apply,{application,start,[mnesia,permanent]}}, UpInstructionsT), - ?line true = lists:member({apply,{application,start,[sasl,transient]}}, UpInstructionsT), + ?line true = lists:member({apply,{application,start,[runtime_tools,transient]}}, UpInstructionsT), ?line true = lists:member({apply,{application,start,[webtool,temporary]}}, UpInstructionsT), ?line true = lists:member({apply,{application,load,[snmp]}}, UpInstructionsT), ?line false = lists:any(fun({apply,{application,_,[xmerl|_]}}) -> true; (_) -> false end, UpInstructionsT), ?line [point_of_no_return | DownInstructionsT] = DownInstructions, ?line true = lists:member({apply,{application,stop,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[sasl]}}, DownInstructionsT), + ?line true = lists:member({apply,{application,stop,[runtime_tools]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[webtool]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[snmp]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[xmerl]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[sasl]}}, DownInstructionsT), + ?line true = lists:member({apply,{application,unload,[runtime_tools]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[webtool]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[snmp]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[xmerl]}}, DownInstructionsT), ok. +%% regexp_relup +regexp_relup(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir,LatestName} = create_script(latest_small,Config), + ?line {_LatestDir0,LatestName0} = create_script(latest_small0,Config), + ?line {_LatestDir1,LatestName1} = create_script(latest_small2,Config), + + ?line DataDir = filename:absname(?copydir), + ?line P = [fname([DataDir, d_regexp_appup, lib, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(LatestDir), + + %% Upgrade fe 2.1 -> 3.1, and downgrade 2.1 -> 3.1 + %% Shall match the first entry if fe-3.1 appup. + ?line {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName0], [LatestName0], + [{path, P}, silent]), + ?line ok = check_relup([{fe, "3.1"}], [{fe, "2.1"}]), + + %% Upgrade fe 2.1.1 -> 3.1 + %% Shall match the second entry in fe-3.1 appup. Have added a + %% restart_emulator instruction there to distinguish it from + %% the first entry... + ?line {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName1], [], [{path, P}, silent]), + ?line ok = check_relup_up_only([{fe, "3.1"}]), + ?line ok = check_restart_emulator_up_only(), + + %% Attempt downgrade fe 3.1 -> 2.1.1 + %% Shall not match any entry!! + ?line {error,systools_relup,{no_relup,_,_,_}} = + systools:make_relup(LatestName, [], [LatestName1], [{path, P}, silent]), + + ?line ok = file:set_cwd(OldDir), + + ok. + + +%% For upgrade of erts - create a boot file which is a hybrid between +%% old and new release - i.e. starts erts, kernel, stdlib, sasl from +%% new release, all other apps from old release. +normal_hybrid(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1,Config), + ?line {_Dir2,Name2} = create_script(current_all,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line ok = file:set_cwd(OldDir), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths, [dummy,args]), + + ?line {script,{"Test release","tmp_vsn"},Script} = binary_to_term(Hybrid), + ct:log("~p.~n",[Script]), + + %% Check that all paths to base apps are replaced by paths from BaseLib + Boot1Str = io_lib:format("~p~n",[binary_to_term(Boot1)]), + HybridStr = io_lib:format("~p~n",[binary_to_term(Hybrid)]), + ReOpts = [global,{capture,first,list},unicode], + ?line {match,OldKernelMatch} = re:run(Boot1Str,"kernel-[0-9\.]+",ReOpts), + ?line {match,OldStdlibMatch} = re:run(Boot1Str,"stdlib-[0-9\.]+",ReOpts), + ?line {match,OldSaslMatch} = re:run(Boot1Str,"sasl-[0-9\.]+",ReOpts), + + ?line nomatch = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts), + ?line nomatch = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts), + ?line nomatch = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts), + ?line {match,NewKernelMatch} = re:run(HybridStr,"testkernelpath",ReOpts), + ?line {match,NewStdlibMatch} = re:run(HybridStr,"teststdlibpath",ReOpts), + ?line {match,NewSaslMatch} = re:run(HybridStr,"testsaslpath",ReOpts), + + NewKernelN = length(NewKernelMatch), + ?line NewKernelN = length(OldKernelMatch), + NewStdlibN = length(NewStdlibMatch), + ?line NewStdlibN = length(OldStdlibMatch), + NewSaslN = length(NewSaslMatch), + ?line NewSaslN = length(OldSaslMatch), + + %% Check that application load instruction has correct versions + Apps = application:loaded_applications(), + {_,_,KernelVsn} = lists:keyfind(kernel,1,Apps), + {_,_,StdlibVsn} = lists:keyfind(stdlib,1,Apps), + {_,_,SaslVsn} = lists:keyfind(sasl,1,Apps), + + ?line [KernelInfo] = [I || {kernelProcess,application_controller, + {application_controller,start, + [{application,kernel,I}]}} <- Script], + ?line [StdlibInfo] = [I || {apply, + {application,load, + [{application,stdlib,I}]}} <- Script], + ?line [SaslInfo] = [I || {apply, + {application,load, + [{application,sasl,I}]}} <- Script], + + ?line {vsn,KernelVsn} = lists:keyfind(vsn,1,KernelInfo), + ?line {vsn,StdlibVsn} = lists:keyfind(vsn,1,StdlibInfo), + ?line {vsn,SaslVsn} = lists:keyfind(vsn,1,SaslInfo), + + %% Check that new_emulator_upgrade call is added + ?line [_,{apply,{release_handler,new_emulator_upgrade,[dummy,args]}}|_] = + lists:reverse(Script), + + %% Check that db-1.0 and fe-3.1 are used (i.e. vsns from old release) + %% And that fe is in there (it exists in old rel but not in new) + ?line {match,DbMatch} = re:run(HybridStr,"db-[0-9\.]+",ReOpts), + ?line {match,[_|_]=FeMatch} = re:run(HybridStr,"fe-[0-9\.]+",ReOpts), + ?line true = lists:all(fun(["db-1.0"]) -> true; + (_) -> false + end, + DbMatch), + ?line true = lists:all(fun(["fe-3.1"]) -> true; + (_) -> false + end, + FeMatch), + + %% Check that script has same length as old script, plus one (the + %% new_emulator_upgrade apply) + {_,_,Old} = binary_to_term(Boot1), + OldLength = length(Old), + NewLength = length(Script), + ?line NewLength = OldLength + 1, + + ok. + +%% Check that systools_make:make_hybrid_boot fails with a meaningful +%% error message if the FromBoot does not include the sasl +%% application. +hybrid_no_old_sasl(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config), + ?line {_Dir2,Name2} = create_script(current_all,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {error,{app_not_replaced,sasl}} = + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ?line ok = file:set_cwd(OldDir), + ok. + + +%% Check that systools_make:make_hybrid_boot fails with a meaningful +%% error message if the ToBoot does not include the sasl +%% application. +hybrid_no_new_sasl(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1,Config), + ?line {_Dir2,Name2} = create_script(current_all_no_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {error,{app_not_found,sasl}} = + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ?line ok = file:set_cwd(OldDir), + ok. + + + otp_6226(suite) -> []; otp_6226(doc) -> @@ -1388,7 +1777,8 @@ otp_6226(Config) when is_list(Config) -> fname([LibDir, 'db-1.0', ebin]), fname([LibDir, 'fe-3.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1656,165 +2046,95 @@ tar_name(Name) -> Name ++ ".tar.gz". create_script(latest,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest,Config,"4.4",Apps); create_script(latest_no_mod_vsn,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATESTNOMOD\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"3.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"3.1"},{fe,"3.1"}], + do_create_script(latest_no_mod_vsn,Config,"4.4",Apps); create_script(latest0,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-1'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0,Config,"4.4",Apps); +create_script(latest0_current_erts,Config) -> + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0_current_erts,Config,current,Apps); create_script(latest1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1,Config,"4.4",Apps); +create_script(latest1_no_sasl,Config) -> + Apps = [{kernel,"1.0"},{stdlib,"1.0"},{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1_no_sasl,Config,"4.4",Apps); create_script(latest2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-2'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 1\", \"LATEST2\"}, \n" - " {erts, \"4.3\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"2.1"}], + do_create_script(latest2,Config,"4.3",Apps); create_script(latest_small,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"3.1"}], + do_create_script(latest_small,Config,"4.4",Apps); create_script(latest_small0,Config) -> %Differs in fe vsn - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small0'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"2.1"}], + do_create_script(latest_small0,Config,"4.4",Apps); create_script(latest_small1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small1'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"500.18.7\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"500.18.7"}], + do_create_script(latest_small1,Config,"4.4",Apps); +create_script(latest_small2,Config) -> + Apps = core_apps("1.0") ++ [{fe,"2.1.1"}], + do_create_script(latest_small2,Config,"4.4",Apps); create_script(latest_nokernel,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-nokernel'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST_NOKERNEL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_nokernel,Config,"4.4",Apps); create_script(latest_app_start_type1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type1), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "1"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current), + do_create_script(latest_app_start_type1,Config,current,Apps); create_script(latest_app_start_type2,Config) -> + OtherApps = [{mnesia,current,permanent}, + {runtime_tools,current,transient}, + {webtool,current,temporary}, + {snmp,current,load}, + {xmerl,current,none}], + Apps = core_apps(current) ++ OtherApps, + do_create_script(latest_app_start_type2,Config,current,Apps); +create_script(current_all_no_sasl,Config) -> + Apps = [{kernel,current},{stdlib,current},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_no_sasl,Config,current,Apps); +create_script(current_all,Config) -> + Apps = core_apps(current) ++ [{db,"2.1"}], + do_create_script(current_all,Config,current,Apps); +create_script(current_all_future_erts,Config) -> + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_erts,Config,"99.99",Apps); +create_script(current_all_future_sasl,Config) -> + Apps = [{kernel,current},{stdlib,current},{sasl,"9.9"},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_sasl,Config,current,Apps). + + +do_create_script(Id,Config,ErtsVsn,AppVsns) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type2), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line OtherApps = [{mnesia,permanent}, - {sasl,transient}, - {webtool,temporary}, - {snmp,load}, - {xmerl,none}], - ?line lists:foreach(fun({App,_}) -> application:load(App) end, - OtherApps), - ?line Loaded = application:loaded_applications(), - ?line OtherAppsRel = - lists:map(fun({App,StartType}) -> - {_,_,Ver} = lists:keyfind(App,1,Loaded), - {App,Ver,StartType} - end, - OtherApps), + ?line Name = fname(PrivDir, Id), ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "2"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer} | OtherAppsRel]}, + ?line RelfileContent = + {release,{"Test release", string:to_upper(atom_to_list(Id))}, + {erts,erts_vsn(ErtsVsn)}, + app_vsns(AppVsns)}, ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}. +core_apps(Vsn) -> + [{App,Vsn} || App <- [kernel,stdlib,sasl]]. + +app_vsns(AppVsns) -> + [{App,app_vsn(App,Vsn)} || {App,Vsn} <- AppVsns] ++ + [{App,app_vsn(App,Vsn),Type} || {App,Vsn,Type} <- AppVsns]. +app_vsn(App,current) -> + application:load(App), + {ok,Vsn} = application:get_key(App,vsn), + Vsn; +app_vsn(_App,Vsn) -> + Vsn. + +erts_vsn(current) -> erlang:system_info(version); +erts_vsn(Vsn) -> Vsn. + + create_include_files(inc1, Config) -> ?line PrivDir = ?privdir, ?line Name = fname(PrivDir, inc1), diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..3cb0b0c2cf --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app new file mode 100644 index 0000000000..3a5c0ddd9b --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "500.18.7"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app new file mode 100644 index 0000000000..c7ba1dfe91 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..47ea248720 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app new file mode 100644 index 0000000000..0696e2494c --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "3.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup new file mode 100644 index 0000000000..6b99c47e53 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup @@ -0,0 +1,28 @@ +%% -*- erlang -*- +%% Release upgrade script for fe (front end) +%% + +{ + "3.1", + %% Upgrade from: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe1, fe2]} + ]}, + {<<"2(\\.[0-9]+)+">>, % matches 2.X.Y... in full length + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge,[fe1, fe2]}, + restart_emulator]} + ], + + %% Downgrade to: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe2, soft, soft_purge, soft_purge, []}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe2]} + ]} + ] +}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app new file mode 100644 index 0000000000..3bcc1a4619 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE FUTURE SASL"}, + {vsn, "9.9"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup new file mode 100644 index 0000000000..cff0c69b6e --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "9.9", + [{<<".+">>,[restart_new_emulator]} + ], + + [{<<".+">>,[restart_new_emulator]} + ] +}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app new file mode 100644 index 0000000000..aaeb37fa4d --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE SASL"}, + {vsn, "1.0"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup new file mode 100644 index 0000000000..796a1e7368 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "1.0", + [ + ], + + [ + ] +}. diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl index bb93f38fa7..2ab9e269f9 100644 --- a/lib/sasl/test/systools_rc_SUITE.erl +++ b/lib/sasl/test/systools_rc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,14 +21,15 @@ -include_lib("test_server/include/test_server.hrl"). -include_lib("sasl/src/systools.hrl"). -export([all/0,groups/0,init_per_group/2,end_per_group/2, - syntax_check/1, translate/1, translate_app/1]). + syntax_check/1, translate/1, translate_app/1, + translate_emulator_restarts/1]). %%----------------------------------------------------------------- %% erl -compile systools_rc_SUITE @i ../src/ @i ../../test_server/include/ %% c(systools_rc_SUITE, [{i, "../src"}, {i, "../../test_server/include"}]). %%----------------------------------------------------------------- all() -> - [syntax_check, translate, translate_app]. + [syntax_check, translate, translate_app, translate_emulator_restarts]. groups() -> []. @@ -87,7 +88,8 @@ syntax_check(Config) when is_list(Config) -> {sync_nodes, id1, {m, f, [a]}}, {sync_nodes, id2, [cp1, cp2]}, {apply, {m,f,[a]}}, - restart_new_emulator + restart_new_emulator, + restart_emulator ], ?line {ok, _} = systools_rc:translate_scripts([S2], Apps, []), S3 = [{apply, {m, f, a}}], @@ -486,3 +488,85 @@ io:format("X2=~p~n", [X2]), {purge,[pelle,kalle]}, {apply,{application,unload,[pelle]}}] = X3, ?line ok. + + +translate_emulator_restarts(_Config) -> + Apps = + [#application{name = test, + description = "TEST", + vsn = "1.0", + modules = [{foo,1},{bar,1},{baz,1}], + regs = [], + mod = {sasl, []}}, + #application{name = test, + description = "TEST2", + vsn = "1.0", + modules = [{x,1},{y,1},{z,1}], + regs = [], + mod = {sasl, []}}], + %% restart_new_emulator + Up1 = [{update, foo, soft, soft_purge, soft_purge, []},restart_new_emulator], + ?line {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}] = X1, + + %% restart_emulator + Up2 = [{update, foo, soft, soft_purge, soft_purge, []},restart_emulator], + ?line {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), + ?line [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X2, + + %% restart_emulator + restart_new_emulator + Up3 = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + ?line {ok, X3} = systools_rc:translate_scripts([Up3], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X3, + + %% restart_emulator + restart_new_emulator + Up4a = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + Up4b = [restart_new_emulator, + {update, x, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_emulator], + ?line {ok, X4} = systools_rc:translate_scripts([Up4a,Up4b], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo,x]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + {suspend,[x]}, + {load,{x,soft_purge,soft_purge}}, + {resume,[x]}, + restart_emulator] = X4, + + %% only restart_new_emulator + Up5 = [restart_new_emulator], + ?line {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []), + ?line [restart_new_emulator, + point_of_no_return] = X5, + + %% only restart_emulator + Up6 = [restart_emulator], + ?line {ok, X6} = systools_rc:translate_scripts([Up6], Apps, []), + ?line [point_of_no_return, + restart_emulator] = X6, + + ok. diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl new file mode 100644 index 0000000000..eeef721647 --- /dev/null +++ b/lib/sasl/test/test_lib.hrl @@ -0,0 +1,3 @@ +-define(ertsvsn,"4.4"). +-define(kernelvsn,"2.14.3"). +-define(stdlibvsn,"1.17.3"). diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index 2db134af48..23694f1399 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.1.10 +SASL_VSN = 2.2 diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile index aa9431477c..df597c8ba7 100644 --- a/lib/snmp/doc/src/Makefile +++ b/lib/snmp/doc/src/Makefile @@ -28,14 +28,6 @@ VSN = $(SNMP_VSN) APPLICATION=snmp # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -88,40 +80,10 @@ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6) MAN7_FILES = $(MIB_FILES:$(MIBSDIR)/%.mib=$(MAN7DIR)/%.7) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = \ - $(XML_REF1_FILES:%.xml=%.tex) \ - $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_REF6_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_PART_FILES = $(XML_PART_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = snmp-$(VSN).pdf -TOP_PS_FILE = snmp-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - @echo "building $(TOP_PDF_FILE)" - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - @echo "building $(TOP_PS_FILE)" - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -TOP_HTML_FILES = $(INDEX_TARGET) - -endif - INDEX_FILE = index.html INDEX_SRC = $(INDEX_FILE).src INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE) @@ -141,8 +103,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif # Copy them to ../html $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man ldocs: local_docs $(INDEX_TARGET) @@ -157,47 +117,6 @@ html2: html $(INDEX_TARGET) clean clean_docs: clean_html clean_man clean_pdf rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(TOP_HTML_FILES) gifs - -html2: gifs $(TOP_HTML_FILES) $(HTML_FILES) $(HTML_REF1_FILES) $(HTML_REF3_FILES) $(HTML_REF6_FILES) $(HTML_CHAP_FILES) - -clean: clean_tex clean_html clean_man clean_docs - - -clean_tex: - @echo "cleaning tex:" - rm -f $(TEX_FILES_USERS_GUIDE) - rm -f $(TEX_FILES_REF_MAN) - rm -f $(TEX_PART_FILES) - rm -f $(TEX_FILES_BOOK) - -clean_docs: - @echo "cleaning docs:" - rm -f $(TOP_PDF_FILE) - rm -f $(TOP_PS_FILE) - rm -f core $(LATEX_CLEAN) - - -$(HTML_PART_FILES): notes.xml - -endif - $(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk # Create top make file sed -e 's;%VSN%;$(VSN);' $< > $@ # inserting version number @@ -250,8 +169,6 @@ $(MAN1DIR)/snmpc.1: snmpc_cmd.xml include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -268,55 +185,13 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man7 $(INSTALL_DATA) $(MAN7DIR)/* $(RELEASE_PATH)/man/man7 -else - - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man1 - $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1 - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 - $(INSTALL_DIR) $(RELEASE_PATH)/man/man6 - $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6 - $(INSTALL_DIR) $(RELEASE_PATH)/man/man7 - $(INSTALL_DATA) $(MAN7_FILES) $(RELEASE_PATH)/man/man7 - $(INSTALL_DATA) $(TOP_HTML_FILES) \ - $(RELSYSDIR)/doc -endif -endif - -endif - release_spec: -ifdef DOCSUPPORT info: info_xml info_man info_html @echo "MAN1DIR: $(MAN1DIR)" @echo "MAN3DIR: $(MAN3DIR)" @echo "MAN6DIR: $(MAN6DIR)" @echo "MAN7DIR: $(MAN7DIR)" -else -info: info_xml info_man info_html info_tex - @echo "DVI2PS = $(DVI2PS)" - @echo "DVIPS_FLAGS = $(DVIPS_FLAGS)" - @echo "" - @echo "DISTILL = $(DISTILL)" - @echo "DISTILL_FLAGS = $(DISTILL_FLAGS)" -endif info_man: @echo "man files:" @@ -362,14 +237,3 @@ info_html: @echo "HTML_REF3_FILES = $(HTML_REF3_FILES)" @echo "HTML_REF6_FILES = $(HTML_REF6_FILES)" @echo "HTML_CHAP_FILES = $(HTML_CHAP_FILES)" - -info_tex: - @echo "tex files:" - @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)" - @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)" - @echo "TEX_PART_FILES = $(TEX_PART_FILES)" - @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)" - -ifndef DOCSUPPORT -include depend.mk -endif diff --git a/lib/snmp/doc/src/depend.mk b/lib/snmp/doc/src/depend.mk deleted file mode 100644 index 20a523dd8c..0000000000 --- a/lib/snmp/doc/src/depend.mk +++ /dev/null @@ -1,83 +0,0 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode - -# %CopyrightBegin% -# -# Copyright Ericsson AB 2004-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# 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 online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% - -$(HTMLDIR)/part_notes.html: \ - part_notes_history.xml \ - part_notes.xml \ - notes_history.xml \ - notes.xml - -$(HTMLDIR)/part.html: \ - part.xml \ - snmp_intro.xml \ - snmp_agent_funct_descr.xml \ - snmp_manager_funct_descr.xml \ - snmp_mib_compiler.xml \ - snmp_config.xml \ - snmp_agent_config_files.xml \ - snmp_manager_config_files.xml \ - snmp_impl_example_agent.xml \ - snmp_impl_example_manager.xml \ - snmp_instr_functions.xml \ - snmp_def_instr_functions.xml \ - snmp_agent_netif.xml \ - snmp_manager_netif.xml \ - snmp_audit_trail_log.xml \ - snmp_advanced_agent.xml \ - snmp_app_a.xml \ - snmp_app_b.xml - -$(HTMLDIR)/ref_man.html: \ - ref_man.xml \ - snmp_app.xml \ - snmp.xml \ - snmpc.xml \ - snmpc_cmd.xml \ - snmpa.xml \ - snmpa_conf.xml \ - snmpa_discovery_handler.xml \ - snmpa_error_report.xml \ - snmpa_error.xml \ - snmpa_error_io.xml \ - snmpa_error_logger.xml \ - snmpa_local_db.xml \ - snmpa_mpd.xml \ - snmpa_network_interface.xml \ - snmpa_network_interface_filter.xml \ - snmpa_notification_delivery_info_receiver.xml \ - snmpa_notification_filter.xml \ - snmpa_supervisor.xml \ - snmp_community_mib.xml \ - snmp_framework_mib.xml \ - snmp_generic.xml \ - snmp_index.xml \ - snmp_notification_mib.xml \ - snmp_pdus.xml \ - snmp_standard_mib.xml \ - snmp_target_mib.xml \ - snmp_user_based_sm_mib.xml \ - snmp_view_based_acm_mib.xml \ - snmpm.xml \ - snmpm_conf.xml \ - snmpm_mpd.xml \ - snmpm_network_interface.xml \ - snmpm_network_interface_filter.xml \ - snmpm_user.xml - - diff --git a/lib/snmp/doc/src/make.dep b/lib/snmp/doc/src/make.dep deleted file mode 100644 index 223e197f25..0000000000 --- a/lib/snmp/doc/src/make.dep +++ /dev/null @@ -1,77 +0,0 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode - -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# 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 online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% - -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex snmp.tex snmp_advanced_agent.tex \ - snmp_agent_config_files.tex snmp_agent_funct_descr.tex \ - snmp_agent_netif.tex snmp_app.tex snmp_app_a.tex \ - snmp_app_b.tex snmp_audit_trail_log.tex \ - snmp_community_mib.tex \ - snmp_config.tex snmp_def_instr_functions.tex \ - snmp_framework_mib.tex snmp_generic.tex \ - snmp_impl_example_agent.tex \ - snmp_impl_example_manager.tex snmp_index.tex \ - snmp_instr_functions.tex snmp_intro.tex \ - snmp_manager_config_files.tex \ - snmp_manager_funct_descr.tex snmp_manager_netif.tex \ - snmp_mib_compiler.tex snmp_notification_mib.tex \ - snmp_pdus.tex snmp_standard_mib.tex snmp_target_mib.tex \ - snmp_user_based_sm_mib.tex snmp_view_based_acm_mib.tex \ - snmpa.tex snmpa_conf.tex snmpa_error.tex snmpa_error_io.tex \ - snmpa_error_logger.tex snmpa_error_report.tex \ - snmpa_local_db.tex snmpa_mpd.tex \ - snmpa_discovery_handler.tex \ - snmpa_network_interface.tex \ - snmpa_network_interface_filter.tex \ - snmpa_notification_delivery_info_receiver.tex \ - snmpa_notification_filter.tex \ - snmpa_supervisor.tex \ - snmpc.tex snmpc_cmd.tex snmpm.tex snmpm_conf.tex snmpm_mpd.tex \ - snmpm_network_interface.tex snmpm_network_interface_filter.tex \ - snmpm_user.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: MIB_mechanism.ps snmp-um-1-image-1.ps snmp-um-1-image-2.ps \ - snmp-um-1-image-3.ps - -book.dvi: snmp_agent_netif_1.ps - -book.dvi: getnext1.ps getnext2.ps getnext3.ps getnext4.ps - -book.dvi: snmp_manager_netif_1.ps - diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 9e1a060dee..fd5a548b16 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -32,6 +32,120 @@ <file>notes.xml</file> </header> + + <section> + <title>SNMP Development Toolkit 4.21.3</title> + <p>Version 4.21.3 supports code replacement in runtime from/to + version 4.21.2, 4.21.1, 4.21 and 4.20.1. </p> + + <section> + <title>Improvements and new features</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[compiler] Improved version info printout. </p> + <p>Own Id: OTP-9618</p> + </item> + + </list> + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[compiler] Fix the <c>--warnings/--W</c> option parsing in the + <seealso marker="snmpc(command)#option_warnings">snmpc</seealso> + wrapper (e)script. + The short warning option was incorrectly <c>--w</c>, instead + of as documented <c>--W</c>. This has now been corrected. </p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Tuncer Ayaz</p> + <p>Own Id: OTP-9718</p> + </item> + + </list> + + </section> + + + <section> + <title>Incompatibilities</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[compiler] The short warning option has been changed from + <c>--w</c> to <c>--W</c> to comply with the documentation. </p> + <p>Tuncer Ayaz</p> + <p>Own Id: OTP-9718</p> + </item> + + + </list> + </section> + + </section> <!-- 4.21.3 --> + + + <section> + <title>SNMP Development Toolkit 4.21.2</title> + <p>Version 4.21.2 supports code replacement in runtime from/to + version 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>Bad note store GC timer deactivation. + Wrong field in the state record was set (timeout instead active). </p> + <p>Stefan Grundmann</p> + <p>Own Id: OTP-9690</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Bad note store GC timer deactivation. + Wrong field in the state record was set (timeout instead active). </p> + <p>Stefan Grundmann</p> + <p>Own Id: OTP-9690</p> + </item> + + </list> + </section> + + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.2 --> + + <section> <title>SNMP Development Toolkit 4.21.1</title> <p>Version 4.21.1 supports code replacement in runtime from/to @@ -806,927 +920,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols). </section> <!-- 4.15 --> - <section> - <title>SNMP Development Toolkit 4.14</title> - - <p>Version 4.14 supports code replacement in runtime from/to - version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[compiler] Include object- and notification groups in the - compiled mib. - This will make it possible to import groups from other mibs. </p> - <p>Also the SNMPv2-MIB-file has been updated to a more - up-to-date version. </p> - <p>Own Id: OTP-8223</p> - <!-- <p>Aux Id: Seq 11383</p> --> - </item> - - <item> - <p>[manager] Added support for message filtering in the - network interface module provided with the application. - The component that actually make the filter decisions - is the network interface filter module. This module - must implement the - <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso> - for message filtering. - See also the Configuring chapter of - the User's Guide to see how to configure this feature. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the filter options.</p> - <p>Own Id: OTP-8228</p> - <p>Aux Id: Seq 11411</p> - </item> - - <item> - <p>The MIBs delivered as part of the application is now - also available as man pages, section 7. </p> - <p>Own Id: OTP-8237</p> - <!-- <p>Aux Id: Seq 11383</p> --> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] The main agent type header file contained some miss-information - regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.</p> - <p>Own Id: OTP-8116</p> - <p>Aux Id: Seq 11312</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.14 --> - - - <section> - <title>SNMP Development Toolkit 4.13.5</title> - - <p>Version 4.13.5 supports code replacement in runtime from/to - version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[agent] Improved the cache handling of the mib server. </p> - <p>A number of new functions and config options for the mib server - cache has been added. </p> - <p>See - <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>, - <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>, - <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>, - <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and - <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p> - <p>See also the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the mib server cache options.</p> - <p>Own Id: OTP-8182</p> - <p>Aux Id: Seq 11383</p> - </item> - - <item> - <p>[agent] A manager could no longer use the SNMPv3 user "initial" - as this was interpretated as the first step of the discovery. </p> - <p>Introduced a new terminating option, <c>trigger_username</c> to - make it possible to configure the username the agent reacts to. - Default is <c>""</c>. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the discovery options.</p> - <p>Own Id: OTP-8120</p> - <p>Aux Id: Seq 11361</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] The main agent type header file contained some miss-information - regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.</p> - <p>Own Id: OTP-8116</p> - <p>Aux Id: Seq 11312</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.5 --> - - - <section> - <title>SNMP Development Toolkit 4.13.4</title> - - <p>Version 4.13.4 supports code replacement in runtime from/to - version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Originating discovery problems. </p> - <p>Invalid state variable update during second stage of - discovery causes master agent crash. </p> - <p>Also the net_if process failed to activate socket - ({active, once}) after first discovery response was sent. </p> - <p>Own Id: OTP-8044</p> - <p>Aux Id: Seq 11295</p> - </item> - - <item> - <p>[agent] Terminating discovery problem. </p> - <p>The reply to the second stage request should include a - varbind with <c>usmStatsNotInTimeWindows</c>.</p> - <p>Own Id: OTP-8062</p> - <p>Aux Id: Seq 11318</p> - </item> - - <item> - <p>[agent] Originating discovery improvement. </p> - <p>Added the ExtraInfo argument to the - <seealso marker="snmpa#discovery">discovery</seealso> function. - This argument will be passed on to the stage1_finish callback - function. Also, the - <seealso marker="snmpa#discovery">discovery</seealso> function - will now always return <c>{ok, ManagerEngineID}</c> on successful - discovery. </p> - <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso> - behaviour updated accordingly. </p> - <p>Own Id: OTP-8098</p> - <p>Aux Id: Seq 11346</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.4 --> - - - <section> - <title>SNMP Development Toolkit 4.13.3</title> - - <p>Version 4.13.3 supports code replacement in runtime from/to - version 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] A request for an oid of type BITS was actually - returned as OCTET STRING. </p> - <p>Values of type BITS are encoded as OCTET STRING, - which makes it impossible for the decoder to know that - they should really be of type BITS. - Instead, this has to be done higher up in the stack, where - there is knowledge of the MIB (assuming that the mib has - been loaded, there is info about the type of the mibentry). </p> - <p>This problem has now been fixed, but requires that the MIB - defining this mib-entry is loaded! </p> - <p>The utility function - <seealso marker="snmpm#oid_to_type">oid_to_type</seealso> - has been added, for debug purpose. </p> - <p>The utility function(s) - <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso> - and - <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso> - has also been added. These can be used if the user prefers to - handle the conversion on their own. </p> - <p>Own Id: OTP-8015</p> - <p>Aux Id: Seq 11285</p> - </item> - - <item> - <p>[agent] Fixed some issues with the discovery handling. </p> - <p>Changed the API of the - <seealso marker="snmpa#discovery">discovery</seealso> - function to solve some - of these problems. </p> - <p>Introduced various options for controlling the discovery - process. See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the discovery options.</p> - <p>Own Id: OTP-8020</p> - <p>Aux Id: Seq 11295</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.3 --> - - - <section> - <title>SNMP Development Toolkit 4.13.2</title> - - <p>Version 4.13.2 supports code replacement in runtime from/to - version 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Failure during downed user cleanup. - As part of the cleanup after a crashed user, - the manager attempts to unregister the agents - registered by this user. This however failed, - causing a server crash. </p> - <p>Own Id: OTP-7961</p> - <p>Aux Id: Seq 11275</p> - </item> - - <item> - <p>[manager] Incorrectly documented value type for - IpAddress (ip). The value type for IpAddress is - documented as ip but is actually ia. The value type - ip has been added. The old (not documented) value - type ia still works. </p> - <p>Own Id: OTP-7977</p> - <p>Aux Id: Seq 11279</p> - </item> - - <item> - <p>[manager] EngineId lookup fails when using version-3. </p> - <p>Own Id: OTP-7983</p> - <p>Aux Id: Seq 11275</p> - </item> - - <item> - <p>[agent] As of version 4.13 the possible return values - of the function - <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso> - changed, but this was not documented. </p> - <p>Own Id: OTP-7989</p> - <p>Aux Id: Seq 11275</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.2 --> - - <section> - <title>SNMP Development Toolkit 4.13.1</title> - - <p>Version 4.13.1 supports code replacement in runtime from/to - version 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Registration of users had some issues. </p> - <p>Not all of the registration functions where actually exported - (<seealso marker="snmpm#register_user">register_user/4</seealso> - and - <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>). - This has now been fixed. </p> - <p>Also, the registration did not succeed unless - user implemented the *new* behaviour. This has now - also been fixed (registration succeeds if the user - implements either the new (i.e. updated - <seealso marker="snmpm_user">snmpm_user</seealso>) - or the old user behaviour (<c>snmpm_user_old</c>)). </p> - <p>Own Id: OTP-7902</p> - <p>Aux Id: Seq 11240</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.1 --> - - <section> - <title>SNMP Development Toolkit 4.13</title> -<!-- - <p>Version 4.13 supports code replacement in runtime from/to - version 4.12.1.</p> ---> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Unnecessary use of math:pow/2 could cause problems - on systems without floating point support. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7735</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - <item> - <p>[manager] A major flaw was discovered with the agent handling. </p> - <p>First, <c>TargetName</c> was never used as intended, as a unique - identifier for the target (agent in this case). </p> - <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant - that several agents could have the same <c>TargetName</c>, causing - unpredictable behaviour in the manager. </p> - <p>Third, <c>EngineID</c> was not a mandatory config option and had - furthermore also a <em>default value</em>. </p> - - <p>These problems has been solved in the following way: </p> - <p>First, a new set of api functions has been introduced (and documented): - <seealso marker="snmpm#register_user">register_user/4</seealso>, - <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>, - <seealso marker="snmpm#register_agent">register_agent/3</seealso>, - <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>, - <seealso marker="snmpm#agent_info">agent_info/2</seealso>, - <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>, - <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>, - <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>, - <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>, - <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and - <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso> - that all use <c>TargetName</c> (and not, as previously, <c>Addr</c> - and <c>Port</c>) to identify the agent (also the return value of - <seealso marker="snmpm#which_agents">which_agents</seealso> has - been changed). </p> - <p>Second, for backward compatibility, the old functions still - exist, but are no longer documented and are now wrappers for the - new functions, including erroneous default value for EngineID and - all. The TargetName is however generated from the provided - <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p> - <p>Third, the behaviour of the - <seealso marker="snmpm_user">SNMP manager user</seealso> has - been changed to reflect this, i.e. - <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>, - <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>, - <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>, - <seealso marker="snmpm_user#handle_report">handle_report/3</seealso> - and the return-value of - <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>. - The old (non-documented) callback-functions (using Addr and Port) - will still be called if the agent was registered using the old - registration functions. </p> - - <p>Own Id: OTP-7836</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13 --> - - <section> - <title>SNMP Development Toolkit 4.12.2</title> - <p>Version 4.12.2 supports code replacement in runtime from/to - version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Bad session cache (usm+camv-info) invalidation - could cause user crash, through call(s) to (a number of) - MIB API function(s) (undefined function). </p> - <p>Own Id: OTP-7868</p> - <!-- <p>Aux Id: Seq 11124</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12.2 --> - - <section> - <title>SNMP Development Toolkit 4.12.1</title> - <p>Version 4.12.1 supports code replacement in runtime from/to - version 4.12, 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>Logging of messages with the GetBulk-request PDU - incorrectly produced an erroneous entry in the - log: "An error occurred". </p> - <p>The reason for this was that the PDU-fields - error_status and error_index is re-used for - Non-repeaters and Max-repetitions for - GetBulk-request PDUs, but this was not handled - by the logging code. </p> - <p>Own Id: OTP-7695</p> - <p>Aux Id: Seq 11124</p> - </item> - - <item> - <p>[agent] An attempt to set the row status to active for an - notReady table row, could result in an "inconsistentValue" - error. </p> - <p>The same problem existed when attempting to set row status - to notInService for a row in notReady. </p> - <p>Serge Aleynikov</p> - <p>Own Id: OTP-7698</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12.1 --> - - <section> - <title>SNMP Development Toolkit 4.12</title> - <p>Version 4.12 supports code replacement in runtime from/to - version 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] A simple lookup cache has been added to improve - the mib server lookup performance. </p> - <p>This can be disabled with the mib_server - <seealso marker="snmp_app">cache</seealso> option. </p> - <p>Own Id: OTP-7346</p> - </item> - - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7432</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12 --> - - <section> - <title>SNMP Development Toolkit 4.11.2</title> - <p>Version 4.11.2 supports code replacement in runtime from/to - version 4.11.1 and 4.11. </p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>Added utility functions for transforming DateAndTime - as [int()] to strings; - <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> - and - <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> - <p>Also added new validation function - <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> - <p>Own Id: OTP-7412</p> - <p>Aux Id: Seq 10987</p> - </item> - </list> - --> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Erroneous engine-id check when receiving version 3 - informs. </p> - <p>Own Id: OTP-7570</p> - <p>Aux Id: Seq 11060</p> - </item> - - <item> - <p>Receiving an snmp message with a very large version - number could cause the erlang node to run out of - memory and consequently crash. </p> - <p>The standard specifies the snmp version as an - (unlimited) INTEGER, but today only - 0 (version 1), 1 (version 2) and 3 (version 3) is - actually used. So, when decoding a message, a limit - has been put on the snmp version integer in order - to not allow this kind of a problem. </p> - <p>Own Id: OTP-7575</p> - <p>Aux Id: Seq 11064</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11.2 --> - - - <section> - <title>SNMP Development Toolkit 4.11.1</title> - <p>Version 4.11.1 supports code replacement in runtime from/to - version 4.11.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[compiler] The MIB compiler did not retrieve the REFERENCE part - of a SNMP MIB definition. </p> - <p>This problem has been partly solved. For SNMP tables, - the assocList field of the tables mib-entry record now contains - this info (as <c>{reference, string()}</c>), <em>if</em> the - MIB was compiled with the compiler option <em>+reference</em>. </p> - <p>This solution is temporary, until such time as a permanent - solution (and probably not backward compatible) is devised, which - retrieves and stores all REFERENCE part(s) of a MIB. </p> - <p>See the - <seealso marker="snmpc#compiler_opts">compiler options</seealso> - for more info. </p> - - <p>Serge Aleynikov</p> - <p>Own Id: OTP-7426</p> - </item> - - <item> - <p>Added utility functions for transforming DateAndTime - as [int()] to strings; - <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> - and - <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> - <p>Also added new validation function - <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> - <p>Own Id: OTP-7412</p> - <p>Aux Id: Seq 10987</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7432</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11.1 --> - - <section> - <title>SNMP Development Toolkit 4.11</title> - <p>Version 4.11 supports code replacement in runtime from/to - version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Performance improvements in the case when an SNMP - manager performs an snmpwalk. </p> - <p>Martin Björklund</p> - <p>Own Id: OTP-7201</p> - </item> - - <item> - <p>The API for sending inform(s) has been improved. Also - the documentation has been corrected and updated. See - <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and - <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso> - for more info.</p> - <p>Own Id: OTP-7287</p> - <p>Aux Id: Seq 10926</p> - </item> - - <item> - <p>[agent] Performance of the internal database (local-db) - has been improved.</p> - <p>Own Id: OTP-7319</p> - <p>Aux Id: Seq 10942</p> - </item> - - <item> - <p>[agent] Added utility functions, - <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and - <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>, - for restarting the agent worker processes (in case the agent is - multi-threaded).</p> - <p>Own Id: OTP-7369</p> - </item> - - <item> - <p>Add utility function to - <seealso marker="snmp#read_mib">read</seealso> - a compiled mib. </p> - <p>Own Id: OTP-7371</p> - </item> - - </list> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7377</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11 --> - <!-- section> <title>Release notes history</title> <p>For information about older versions see diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml index 934df87866..722d02afbd 100644 --- a/lib/snmp/doc/src/notes_history.xml +++ b/lib/snmp/doc/src/notes_history.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -33,6 +33,928 @@ </header> <section> + <title>SNMP Development Toolkit 4.14</title> + + <p>Version 4.14 supports code replacement in runtime from/to + version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[compiler] Include object- and notification groups in the + compiled mib. + This will make it possible to import groups from other mibs. </p> + <p>Also the SNMPv2-MIB-file has been updated to a more + up-to-date version. </p> + <p>Own Id: OTP-8223</p> + <!-- <p>Aux Id: Seq 11383</p> --> + </item> + + <item> + <p>[manager] Added support for message filtering in the + network interface module provided with the application. + The component that actually make the filter decisions + is the network interface filter module. This module + must implement the + <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso> + for message filtering. + See also the Configuring chapter of + the User's Guide to see how to configure this feature. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the filter options.</p> + <p>Own Id: OTP-8228</p> + <p>Aux Id: Seq 11411</p> + </item> + + <item> + <p>The MIBs delivered as part of the application is now + also available as man pages, section 7. </p> + <p>Own Id: OTP-8237</p> + <!-- <p>Aux Id: Seq 11383</p> --> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] The main agent type header file contained some miss-information + regarding the type of the entrytype field of the me-record, causing + unneccessary confusion.</p> + <p>Own Id: OTP-8116</p> + <p>Aux Id: Seq 11312</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.14 --> + + + <section> + <title>SNMP Development Toolkit 4.13.5</title> + + <p>Version 4.13.5 supports code replacement in runtime from/to + version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] Improved the cache handling of the mib server. </p> + <p>A number of new functions and config options for the mib server + cache has been added. </p> + <p>See + <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>, + <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>, + <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>, + <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and + <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p> + <p>See also the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the mib server cache options.</p> + <p>Own Id: OTP-8182</p> + <p>Aux Id: Seq 11383</p> + </item> + + <item> + <p>[agent] A manager could no longer use the SNMPv3 user "initial" + as this was interpretated as the first step of the discovery. </p> + <p>Introduced a new terminating option, <c>trigger_username</c> to + make it possible to configure the username the agent reacts to. + Default is <c>""</c>. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the discovery options.</p> + <p>Own Id: OTP-8120</p> + <p>Aux Id: Seq 11361</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] The main agent type header file contained some miss-information + regarding the type of the entrytype field of the me-record, causing + unneccessary confusion.</p> + <p>Own Id: OTP-8116</p> + <p>Aux Id: Seq 11312</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.5 --> + + + <section> + <title>SNMP Development Toolkit 4.13.4</title> + + <p>Version 4.13.4 supports code replacement in runtime from/to + version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Originating discovery problems. </p> + <p>Invalid state variable update during second stage of + discovery causes master agent crash. </p> + <p>Also the net_if process failed to activate socket + ({active, once}) after first discovery response was sent. </p> + <p>Own Id: OTP-8044</p> + <p>Aux Id: Seq 11295</p> + </item> + + <item> + <p>[agent] Terminating discovery problem. </p> + <p>The reply to the second stage request should include a + varbind with <c>usmStatsNotInTimeWindows</c>.</p> + <p>Own Id: OTP-8062</p> + <p>Aux Id: Seq 11318</p> + </item> + + <item> + <p>[agent] Originating discovery improvement. </p> + <p>Added the ExtraInfo argument to the + <seealso marker="snmpa#discovery">discovery</seealso> function. + This argument will be passed on to the stage1_finish callback + function. Also, the + <seealso marker="snmpa#discovery">discovery</seealso> function + will now always return <c>{ok, ManagerEngineID}</c> on successful + discovery. </p> + <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso> + behaviour updated accordingly. </p> + <p>Own Id: OTP-8098</p> + <p>Aux Id: Seq 11346</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.4 --> + + + <section> + <title>SNMP Development Toolkit 4.13.3</title> + + <p>Version 4.13.3 supports code replacement in runtime from/to + version 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] A request for an oid of type BITS was actually + returned as OCTET STRING. </p> + <p>Values of type BITS are encoded as OCTET STRING, + which makes it impossible for the decoder to know that + they should really be of type BITS. + Instead, this has to be done higher up in the stack, where + there is knowledge of the MIB (assuming that the mib has + been loaded, there is info about the type of the mibentry). </p> + <p>This problem has now been fixed, but requires that the MIB + defining this mib-entry is loaded! </p> + <p>The utility function + <seealso marker="snmpm#oid_to_type">oid_to_type</seealso> + has been added, for debug purpose. </p> + <p>The utility function(s) + <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso> + and + <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso> + has also been added. These can be used if the user prefers to + handle the conversion on their own. </p> + <p>Own Id: OTP-8015</p> + <p>Aux Id: Seq 11285</p> + </item> + + <item> + <p>[agent] Fixed some issues with the discovery handling. </p> + <p>Changed the API of the + <seealso marker="snmpa#discovery">discovery</seealso> + function to solve some + of these problems. </p> + <p>Introduced various options for controlling the discovery + process. See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the discovery options.</p> + <p>Own Id: OTP-8020</p> + <p>Aux Id: Seq 11295</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.3 --> + + + <section> + <title>SNMP Development Toolkit 4.13.2</title> + + <p>Version 4.13.2 supports code replacement in runtime from/to + version 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Failure during downed user cleanup. + As part of the cleanup after a crashed user, + the manager attempts to unregister the agents + registered by this user. This however failed, + causing a server crash. </p> + <p>Own Id: OTP-7961</p> + <p>Aux Id: Seq 11275</p> + </item> + + <item> + <p>[manager] Incorrectly documented value type for + IpAddress (ip). The value type for IpAddress is + documented as ip but is actually ia. The value type + ip has been added. The old (not documented) value + type ia still works. </p> + <p>Own Id: OTP-7977</p> + <p>Aux Id: Seq 11279</p> + </item> + + <item> + <p>[manager] EngineId lookup fails when using version-3. </p> + <p>Own Id: OTP-7983</p> + <p>Aux Id: Seq 11275</p> + </item> + + <item> + <p>[agent] As of version 4.13 the possible return values + of the function + <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso> + changed, but this was not documented. </p> + <p>Own Id: OTP-7989</p> + <p>Aux Id: Seq 11275</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.2 --> + + <section> + <title>SNMP Development Toolkit 4.13.1</title> + + <p>Version 4.13.1 supports code replacement in runtime from/to + version 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Registration of users had some issues. </p> + <p>Not all of the registration functions where actually exported + (<seealso marker="snmpm#register_user">register_user/4</seealso> + and + <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>). + This has now been fixed. </p> + <p>Also, the registration did not succeed unless + user implemented the *new* behaviour. This has now + also been fixed (registration succeeds if the user + implements either the new (i.e. updated + <seealso marker="snmpm_user">snmpm_user</seealso>) + or the old user behaviour (<c>snmpm_user_old</c>)). </p> + <p>Own Id: OTP-7902</p> + <p>Aux Id: Seq 11240</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.1 --> + + <section> + <title>SNMP Development Toolkit 4.13</title> +<!-- + <p>Version 4.13 supports code replacement in runtime from/to + version 4.12.1.</p> +--> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Unnecessary use of math:pow/2 could cause problems + on systems without floating point support. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7735</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + <item> + <p>[manager] A major flaw was discovered with the agent handling. </p> + <p>First, <c>TargetName</c> was never used as intended, as a unique + identifier for the target (agent in this case). </p> + <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant + that several agents could have the same <c>TargetName</c>, causing + unpredictable behaviour in the manager. </p> + <p>Third, <c>EngineID</c> was not a mandatory config option and had + furthermore also a <em>default value</em>. </p> + + <p>These problems has been solved in the following way: </p> + <p>First, a new set of api functions has been introduced (and documented): + <seealso marker="snmpm#register_user">register_user/4</seealso>, + <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>, + <seealso marker="snmpm#register_agent">register_agent/3</seealso>, + <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>, + <seealso marker="snmpm#agent_info">agent_info/2</seealso>, + <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>, + <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>, + <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>, + <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>, + <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and + <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso> + that all use <c>TargetName</c> (and not, as previously, <c>Addr</c> + and <c>Port</c>) to identify the agent (also the return value of + <seealso marker="snmpm#which_agents">which_agents</seealso> has + been changed). </p> + <p>Second, for backward compatibility, the old functions still + exist, but are no longer documented and are now wrappers for the + new functions, including erroneous default value for EngineID and + all. The TargetName is however generated from the provided + <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p> + <p>Third, the behaviour of the + <seealso marker="snmpm_user">SNMP manager user</seealso> has + been changed to reflect this, i.e. + <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>, + <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>, + <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>, + <seealso marker="snmpm_user#handle_report">handle_report/3</seealso> + and the return-value of + <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>. + The old (non-documented) callback-functions (using Addr and Port) + will still be called if the agent was registered using the old + registration functions. </p> + + <p>Own Id: OTP-7836</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13 --> + + <section> + <title>SNMP Development Toolkit 4.12.2</title> + <p>Version 4.12.2 supports code replacement in runtime from/to + version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Bad session cache (usm+camv-info) invalidation + could cause user crash, through call(s) to (a number of) + MIB API function(s) (undefined function). </p> + <p>Own Id: OTP-7868</p> + <!-- <p>Aux Id: Seq 11124</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12.2 --> + + <section> + <title>SNMP Development Toolkit 4.12.1</title> + <p>Version 4.12.1 supports code replacement in runtime from/to + version 4.12, 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>Logging of messages with the GetBulk-request PDU + incorrectly produced an erroneous entry in the + log: "An error occurred". </p> + <p>The reason for this was that the PDU-fields + error_status and error_index is re-used for + Non-repeaters and Max-repetitions for + GetBulk-request PDUs, but this was not handled + by the logging code. </p> + <p>Own Id: OTP-7695</p> + <p>Aux Id: Seq 11124</p> + </item> + + <item> + <p>[agent] An attempt to set the row status to active for an + notReady table row, could result in an "inconsistentValue" + error. </p> + <p>The same problem existed when attempting to set row status + to notInService for a row in notReady. </p> + <p>Serge Aleynikov</p> + <p>Own Id: OTP-7698</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12.1 --> + + <section> + <title>SNMP Development Toolkit 4.12</title> + <p>Version 4.12 supports code replacement in runtime from/to + version 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] A simple lookup cache has been added to improve + the mib server lookup performance. </p> + <p>This can be disabled with the mib_server + <seealso marker="snmp_app">cache</seealso> option. </p> + <p>Own Id: OTP-7346</p> + </item> + + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7432</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12 --> + + <section> + <title>SNMP Development Toolkit 4.11.2</title> + <p>Version 4.11.2 supports code replacement in runtime from/to + version 4.11.1 and 4.11. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>Added utility functions for transforming DateAndTime + as [int()] to strings; + <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> + and + <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> + <p>Also added new validation function + <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> + <p>Own Id: OTP-7412</p> + <p>Aux Id: Seq 10987</p> + </item> + </list> + --> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Erroneous engine-id check when receiving version 3 + informs. </p> + <p>Own Id: OTP-7570</p> + <p>Aux Id: Seq 11060</p> + </item> + + <item> + <p>Receiving an snmp message with a very large version + number could cause the erlang node to run out of + memory and consequently crash. </p> + <p>The standard specifies the snmp version as an + (unlimited) INTEGER, but today only + 0 (version 1), 1 (version 2) and 3 (version 3) is + actually used. So, when decoding a message, a limit + has been put on the snmp version integer in order + to not allow this kind of a problem. </p> + <p>Own Id: OTP-7575</p> + <p>Aux Id: Seq 11064</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11.2 --> + + + <section> + <title>SNMP Development Toolkit 4.11.1</title> + <p>Version 4.11.1 supports code replacement in runtime from/to + version 4.11.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[compiler] The MIB compiler did not retrieve the REFERENCE part + of a SNMP MIB definition. </p> + <p>This problem has been partly solved. For SNMP tables, + the assocList field of the tables mib-entry record now contains + this info (as <c>{reference, string()}</c>), <em>if</em> the + MIB was compiled with the compiler option <em>+reference</em>. </p> + <p>This solution is temporary, until such time as a permanent + solution (and probably not backward compatible) is devised, which + retrieves and stores all REFERENCE part(s) of a MIB. </p> + <p>See the + <seealso marker="snmpc#compiler_opts">compiler options</seealso> + for more info. </p> + + <p>Serge Aleynikov</p> + <p>Own Id: OTP-7426</p> + </item> + + <item> + <p>Added utility functions for transforming DateAndTime + as [int()] to strings; + <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> + and + <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> + <p>Also added new validation function + <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> + <p>Own Id: OTP-7412</p> + <p>Aux Id: Seq 10987</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7432</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11.1 --> + + <section> + <title>SNMP Development Toolkit 4.11</title> + <p>Version 4.11 supports code replacement in runtime from/to + version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Performance improvements in the case when an SNMP + manager performs an snmpwalk. </p> + <p>Martin Björklund</p> + <p>Own Id: OTP-7201</p> + </item> + + <item> + <p>The API for sending inform(s) has been improved. Also + the documentation has been corrected and updated. See + <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and + <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso> + for more info.</p> + <p>Own Id: OTP-7287</p> + <p>Aux Id: Seq 10926</p> + </item> + + <item> + <p>[agent] Performance of the internal database (local-db) + has been improved.</p> + <p>Own Id: OTP-7319</p> + <p>Aux Id: Seq 10942</p> + </item> + + <item> + <p>[agent] Added utility functions, + <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and + <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>, + for restarting the agent worker processes (in case the agent is + multi-threaded).</p> + <p>Own Id: OTP-7369</p> + </item> + + <item> + <p>Add utility function to + <seealso marker="snmp#read_mib">read</seealso> + a compiled mib. </p> + <p>Own Id: OTP-7371</p> + </item> + + </list> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7377</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11 --> + + + <section> <title>SNMP Development Toolkit 4.10.3</title> <p>Version 4.10.3 supports code replacement in runtime from/to version 4.10.2, 4.10.1 and 4.10.</p> diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 0b6ea93231..af988fda26 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -22,8 +22,18 @@ %% ----- U p g r a d e ------------------------------------------------------- [ + {"4.21.2", + [ + ] + }, + {"4.21.1", + [ + {update, snmp_note_store, soft, soft_purge, soft_purge, []} + ] + }, {"4.21", [ + {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []} ] }, @@ -40,6 +50,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, @@ -47,76 +58,24 @@ {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] - }, - {"4.20", - [ - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]} - ] - }, - {"4.19", - [ - {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} - ] - } + } ], %% ------D o w n g r a d e --------------------------------------------------- [ + {"4.21.2", + [ + ] + }, + {"4.21.1", + [ + {update, snmp_note_store, soft, soft_purge, soft_purge, []} + ] + }, {"4.21", [ + {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []} ] }, @@ -133,6 +92,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, @@ -140,68 +100,6 @@ {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] - }, - {"4.20", - [ - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]} - ] - }, - {"4.19", - [ - {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} - ] } ] }. diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk index f7084f8bcd..3ee8dc4bec 100644 --- a/lib/snmp/src/compile/depend.mk +++ b/lib/snmp/src/compile/depend.mk @@ -44,6 +44,6 @@ $(EBIN)/snmpc_mib_gram.$(EMULATOR): \ ../../include/snmp_types.hrl \ snmpc_mib_gram.erl -$(BIN)/snmpc: snmpc.src +$(BIN)/snmpc: snmpc.src ../../vsn.mk $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@ chmod 755 $@ diff --git a/lib/snmp/src/compile/snmpc.src b/lib/snmp/src/compile/snmpc.src index f993335b89..868e0929b4 100644 --- a/lib/snmp/src/compile/snmpc.src +++ b/lib/snmp/src/compile/snmpc.src @@ -74,7 +74,7 @@ %% --rrnac %% --version %% --verbosity V -%% --warnings +%% --warnings | --W %% --Werror | --wae | --warnings_as_errors main(Args) when is_list(Args) -> case (catch process_args(Args)) of @@ -221,7 +221,10 @@ process_args([], #state{verbosity = Verbosity0, file = MIB} = State) -> process_args(["--help"|_Args], _State) -> ok; process_args(["--version"|_Args], #state{version = Version, mfv = MFV} = _State) -> - {ok, lists:flatten(io_lib:format("snmpc ~s (~s)", [Version, MFV]))}; + OtpVersion = otp_release(), + {ok, lists:flatten( + io_lib:format("snmpc ~s [Mib format version ~s] (OTP ~s)", + [Version, MFV, OtpVersion]))}; process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State) when (V =:= undefined) -> Verbosity = list_to_atom(Verbosity0), @@ -234,7 +237,7 @@ process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State) process_args(["--verbosity"|_Args], #state{verbosity = V}) when (V =/= undefined) -> e(lists:flatten(io_lib:format("Verbosity already set to ~w", [V]))); -process_args(["--w"|Args], State) -> +process_args(["--W"|Args], State) -> process_args(Args, State#state{warnings = true}); process_args(["--warnings"|Args], State) -> process_args(Args, State#state{warnings = true}); @@ -398,3 +401,17 @@ usage() -> e(Reason) -> throw({error, Reason}). + +otp_release() -> + system_info(otp_release, string). + +system_info(Tag, Type) -> + case (catch erlang:system_info(Tag)) of + {'EXIT', _} -> + "-"; + Info when is_list(Info) andalso (Type =:= string) -> + Info; + Info -> + lists:flatten(io_lib:format("~w", [Info])) + end. + diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl index a21a6209f1..23fccf8a5f 100644 --- a/lib/snmp/src/misc/snmp_note_store.erl +++ b/lib/snmp/src/misc/snmp_note_store.erl @@ -258,10 +258,17 @@ code_change({down, _Vsn}, State, _Extra) -> {ok, NState}; % upgrade -code_change(_Vsn, State, _Extra) -> +code_change(_Vsn, State0, _Extra) -> process_flag(trap_exit, true), - NState = restart_timer(State), - {ok, NState}. + State1 = + case State0 of + #state{timeout = false} -> + State0#state{timeout = ?timeout}; + _ -> + State0 + end, + State2 = restart_timer(State1), + {ok, State2}. %%---------------------------------------------------------- @@ -282,7 +289,7 @@ deactivate_timer(#state{timer = Pid, active = true} = State) -> receive deactivated -> ok end, - State#state{timeout = false}; + State#state{active = false}; deactivate_timer(State) -> State. diff --git a/lib/snmp/test/snmp_manager_user_old.erl b/lib/snmp/test/snmp_manager_user_old.erl index edffc80dd4..edffc80dd4 100755..100644 --- a/lib/snmp/test/snmp_manager_user_old.erl +++ b/lib/snmp/test/snmp_manager_user_old.erl diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index c95e0a22d1..25e3a9470b 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -17,6 +17,6 @@ # # %CopyrightEnd% -SNMP_VSN = 4.21.1 +SNMP_VSN = 4.21.3 PRE_VSN = APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile index c4d8d9901c..c97c99cf52 100644 --- a/lib/ssh/doc/src/Makefile +++ b/lib/ssh/doc/src/Makefile @@ -29,15 +29,6 @@ VSN=$(SSH_VSN) APPLICATION=ssh # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -76,33 +67,10 @@ EXTRA_FILES = \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) - -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf -TOP_PS_FILE = $(APPLICATION)-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -115,8 +83,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -131,32 +97,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) - -endif - man: $(MAN3_FILES) @@ -168,8 +108,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -179,28 +117,5 @@ release_docs_spec: docs $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif release_spec: diff --git a/lib/ssh/doc/src/make.dep b/lib/ssh/doc/src/make.dep deleted file mode 100644 index cfe2f9617b..0000000000 --- a/lib/ssh/doc/src/make.dep +++ /dev/null @@ -1,19 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex ref_man.tex ssh.tex ssh_channel.tex \ - ssh_connection.tex ssh_sftp.tex ssh_sftpd.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml diff --git a/lib/ssh/src/DSS.asn1 b/lib/ssh/src/DSS.asn1 index 77aca3808b..77aca3808b 100755..100644 --- a/lib/ssh/src/DSS.asn1 +++ b/lib/ssh/src/DSS.asn1 diff --git a/lib/ssh/src/PKCS-1.asn1 b/lib/ssh/src/PKCS-1.asn1 index e7d6b18c63..e7d6b18c63 100755..100644 --- a/lib/ssh/src/PKCS-1.asn1 +++ b/lib/ssh/src/PKCS-1.asn1 diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 3f0a06575c..3f0a06575c 100755..100644 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl index 34d4ff8fc1..34d4ff8fc1 100755..100644 --- a/lib/ssh/src/ssh_connect.hrl +++ b/lib/ssh/src/ssh_connect.hrl diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl index 1b9a396f0c..1b9a396f0c 100755..100644 --- a/lib/ssh/src/ssh_dsa.erl +++ b/lib/ssh/src/ssh_dsa.erl diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl index 12180f56bb..12180f56bb 100755..100644 --- a/lib/ssh/src/ssh_file.erl +++ b/lib/ssh/src/ssh_file.erl diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl index 915fd63e4f..915fd63e4f 100755..100644 --- a/lib/ssh/src/ssh_io.erl +++ b/lib/ssh/src/ssh_io.erl diff --git a/lib/ssh/src/ssh_math.erl b/lib/ssh/src/ssh_math.erl index 510eb16aa6..510eb16aa6 100755..100644 --- a/lib/ssh/src/ssh_math.erl +++ b/lib/ssh/src/ssh_math.erl diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl index 91b8285b2e..91b8285b2e 100755..100644 --- a/lib/ssh/src/ssh_rsa.erl +++ b/lib/ssh/src/ssh_rsa.erl diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index f000558100..f000558100 100755..100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl diff --git a/lib/ssh/src/ssh_userauth.hrl b/lib/ssh/src/ssh_userauth.hrl index 8eb2d46ed1..8eb2d46ed1 100755..100644 --- a/lib/ssh/src/ssh_userauth.hrl +++ b/lib/ssh/src/ssh_userauth.hrl diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl index 4a4f1a4291..4a4f1a4291 100755..100644 --- a/lib/ssh/src/ssh_xfer.hrl +++ b/lib/ssh/src/ssh_xfer.hrl diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 70122e4393..50268ae206 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -71,7 +71,8 @@ {fail_if_no_peer_cert, boolean()} {depth, integer()} | {cert, der_encoded()}| {certfile, path()} | - {key, der_encoded()} | {keyfile, path()} | {password, string()} | + {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} | + {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | {cacertfile, path()} | |{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} @@ -139,7 +140,7 @@ <tag>{certfile, path()}</tag> <item>Path to a file containing the user's certificate.</item> - <tag>{key, der_encoded()}</tag> + <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag> <item> The DER encoded users private key. If this option is supplied it will override the keyfile option.</item> diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 29674f30da..1b07e76d6a 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.6", [{restart_application, ssl}]}, {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, @@ -10,6 +11,7 @@ {"4.0.1", [{restart_application, ssl}]} ], [ + {"4.1.6", [{restart_application, ssl}]}, {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 35f9410562..d0693445e0 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -608,8 +608,11 @@ validate_option(certfile, Value) when Value == undefined; is_list(Value) -> validate_option(key, undefined) -> undefined; validate_option(key, {KeyType, Value}) when is_binary(Value), - KeyType == rsa; - KeyType == dsa -> + KeyType == rsa; %% Backwards compatibility + KeyType == dsa; %% Backwards compatibility + KeyType == 'RSAPrivateKey'; + KeyType == 'DSAPrivateKey'; + KeyType == 'PrivateKeyInfo' -> {KeyType, Value}; validate_option(keyfile, Value) when is_list(Value) -> Value; diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 422ea6404b..61876e1158 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -66,7 +66,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef) -> {ok, IssuerId} -> {other, IssuerId}; {error, issuer_not_found} -> - case find_issuer(OtpCert, no_candidate, CertDbHandle) of + case find_issuer(OtpCert, CertDbHandle) of {ok, IssuerId} -> {other, IssuerId}; Other -> @@ -193,7 +193,7 @@ certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) -> {_, true = SelfSigned} -> certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned); {{error, issuer_not_found}, SelfSigned} -> - case find_issuer(OtpCert, no_candidate, CertDbHandle) of + case find_issuer(OtpCert, CertDbHandle) of {ok, {SerialNr, Issuer}} -> certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned); @@ -227,17 +227,24 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned {ok, lists:reverse(Chain)} end. -find_issuer(OtpCert, PrevCandidateKey, CertDbHandle) -> - case ssl_manager:issuer_candidate(PrevCandidateKey, CertDbHandle) of - no_more_candidates -> - {error, issuer_not_found}; - {Key, {_Cert, ErlCertCandidate}} -> - case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of - true -> - public_key:pkix_issuer_id(ErlCertCandidate, self); - false -> - find_issuer(OtpCert, Key, CertDbHandle) - end +find_issuer(OtpCert, CertDbHandle) -> + IsIssuerFun = fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) -> + case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of + true -> + throw(public_key:pkix_issuer_id(ErlCertCandidate, self)); + false -> + Acc + end; + (_, Acc) -> + Acc + end, + + try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of + issuer_not_found -> + {error, issuer_not_found} + catch + {ok, _IssuerId} = Return -> + Return end. is_valid_extkey_usage(KeyUse, client) -> diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 0560a02110..cb2473576a 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -26,7 +26,7 @@ -include_lib("public_key/include/public_key.hrl"). -export([create/0, remove/1, add_trusted_certs/3, - remove_trusted_certs/2, lookup_trusted_cert/4, issuer_candidate/2, + remove_trusted_certs/2, lookup_trusted_cert/4, foldl/3, lookup_cached_certs/2, cache_pem_file/4, uncache_pem_file/2, lookup/2]). -type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}. @@ -127,8 +127,6 @@ uncache_pem_file(File, [_CertsDb, _FileToRefDb, PidToFileDb]) -> exit(Pid, shutdown) end, Pids). - - %%-------------------------------------------------------------------- -spec remove_trusted_certs(pid(), [db_handle()]) -> term(). @@ -161,37 +159,6 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) -> end. %%-------------------------------------------------------------------- --spec issuer_candidate(no_candidate | cert_key() | {file, term()}, term()) -> - {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates. -%% -%% Description: If a certificat does not define its issuer through -%% the extension 'ce-authorityKeyIdentifier' we can -%% try to find the issuer in the database over known -%% certificates. -%%-------------------------------------------------------------------- -issuer_candidate(no_candidate, Db) -> - case ets:first(Db) of - '$end_of_table' -> - no_more_candidates; - {file, _} = Key -> - issuer_candidate(Key, Db); - Key -> - [Cert] = lookup(Key, Db), - {Key, Cert} - end; - -issuer_candidate(PrevCandidateKey, Db) -> - case ets:next(Db, PrevCandidateKey) of - '$end_of_table' -> - no_more_candidates; - {file, _} = Key -> - issuer_candidate(Key, Db); - Key -> - [Cert] = lookup(Key, Db), - {Key, Cert} - end. - -%%-------------------------------------------------------------------- -spec lookup(term(), db_handle()) -> term() | undefined. %% %% Description: Looks up an element in a certificat <Db>. @@ -206,7 +173,18 @@ lookup(Key, Db) -> end, [Pick(Data) || Data <- Contents] end. - +%%-------------------------------------------------------------------- +-spec foldl(fun(), term(), db_handle()) -> term(). +%% +%% Description: Calls Fun(Elem, AccIn) on successive elements of the +%% cache, starting with AccIn == Acc0. Fun/2 must return a new +%% accumulator which is passed to the next call. The function returns +%% the final value of the accumulator. Acc0 is returned if the certifate +%% db is empty. +%%-------------------------------------------------------------------- +foldl(Fun, Acc0, Cache) -> + ets:foldl(Fun, Acc0, Cache). + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 72f02a4362..95a5efd6d0 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -154,18 +154,23 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) -> block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, HashSz, Fragment, Version) -> - try Fun(Key, IV, Fragment) of - Text -> - GBC = generic_block_cipher_from_bin(Text, HashSz), - case is_correct_padding(GBC, Version) of - true -> - Content = GBC#generic_block_cipher.content, - Mac = GBC#generic_block_cipher.mac, - CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, - {Content, Mac, CipherState1}; - false -> - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) - end + try + Text = Fun(Key, IV, Fragment), + GBC = generic_block_cipher_from_bin(Text, HashSz), + Content = GBC#generic_block_cipher.content, + Mac = GBC#generic_block_cipher.mac, + CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, + case is_correct_padding(GBC, Version) of + true -> + {Content, Mac, CipherState1}; + false -> + %% decryption failed or invalid padding, + %% intentionally break Content to make + %% sure a packet with a an invalid padding + %% but otherwise correct data will fail + %% the MAC test later + {<<16#F0, Content/binary>>, Mac, CipherState1} + end catch _:_ -> %% This is a DECRYPTION_FAILED but @@ -500,14 +505,38 @@ hash_size(md5) -> hash_size(sha) -> 20. +%% RFC 5246: 6.2.3.2. CBC Block Cipher +%% +%% Implementation note: Canvel et al. [CBCTIME] have demonstrated a +%% timing attack on CBC padding based on the time required to compute +%% the MAC. In order to defend against this attack, implementations +%% MUST ensure that record processing time is essentially the same +%% whether or not the padding is correct. In general, the best way to +%% do this is to compute the MAC even if the padding is incorrect, and +%% only then reject the packet. For instance, if the pad appears to be +%% incorrect, the implementation might assume a zero-length pad and then +%% compute the MAC. This leaves a small timing channel, since MAC +%% performance depends to some extent on the size of the data fragment, +%% but it is not believed to be large enough to be exploitable, due to +%% the large block size of existing MACs and the small size of the +%% timing signal. +%% +%% implementation note: +%% We return the original (possibly invalid) PadLength in any case. +%% A invalid PadLength will be cought by is_correct_padding/2 +%% generic_block_cipher_from_bin(T, HashSize) -> Sz1 = byte_size(T) - 1, - <<_:Sz1/binary, ?BYTE(PadLength)>> = T, + <<_:Sz1/binary, ?BYTE(PadLength0)>> = T, + PadLength = if + PadLength0 >= Sz1 -> 0; + true -> PadLength0 + end, CompressedLength = byte_size(T) - PadLength - 1 - HashSize, <<Content:CompressedLength/binary, Mac:HashSize/binary, - Padding:PadLength/binary, ?BYTE(PadLength)>> = T, + Padding:PadLength/binary, ?BYTE(PadLength0)>> = T, #generic_block_cipher{content=Content, mac=Mac, - padding=Padding, padding_length=PadLength}. + padding=Padding, padding_length=PadLength0}. generic_stream_cipher_from_bin(T, HashSz) -> Sz = byte_size(T), @@ -516,17 +545,18 @@ generic_stream_cipher_from_bin(T, HashSz) -> #generic_stream_cipher{content=Content, mac=Mac}. -is_correct_padding(_, {3, 0}) -> - true; -%% For interoperability reasons we do not check the padding in TLS 1.0 as it -%% is not strictly required and breaks interopability with for instance -%% Google. -is_correct_padding(_, {3, 1}) -> - true; +%% For interoperability reasons we do not check the padding content in +%% SSL 3.0 and TLS 1.0 as it is not strictly required and breaks +%% interopability with for instance Google. +is_correct_padding(#generic_block_cipher{padding_length = Len, + padding = Padding}, {3, N}) + when N == 0; N == 1 -> + Len == byte_size(Padding); %% Padding must be check in TLS 1.1 and after -is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) -> - list_to_binary(lists:duplicate(Len, Len)) == Padding. - +is_correct_padding(#generic_block_cipher{padding_length = Len, + padding = Padding}, _) -> + Len == byte_size(Padding) andalso + list_to_binary(lists:duplicate(Len, Len)) == Padding. get_padding(Length, BlockSize) -> get_padding_aux(BlockSize, Length rem BlockSize). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index c772697f1d..dda0c27d0c 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -90,12 +90,14 @@ renegotiation, % {boolean(), From | internal | peer} recv_during_renegotiation, %boolean() send_queue, % queue() - terminated = false % + terminated = false, % + allow_renegotiate = true }). -define(DEFAULT_DIFFIE_HELLMAN_PARAMS, - #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME, + #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME, base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}). +-define(WAIT_TO_ALLOW_RENEGOTIATION, 12000). -type state_name() :: hello | abbreviated | certify | cipher | connection. -type gen_fsm_state_return() :: {next_state, state_name(), #state{}} | @@ -303,12 +305,13 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), Hashes0 = ssl_handshake:init_hashes(), - + TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), try ssl_init(SSLOpts0, Role) of {ok, Ref, CertDbHandle, CacheHandle, OwnCert, Key, DHParams} -> Session = State0#state.session, State = State0#state{tls_handshake_hashes = Hashes0, - session = Session#session{own_certificate = OwnCert}, + session = Session#session{own_certificate = OwnCert, + time_stamp = TimeStamp}, cert_db_ref = Ref, cert_db = CertDbHandle, session_cache = CacheHandle, @@ -351,8 +354,7 @@ hello(start, #state{host = Host, port = Port, role = client, State1 = State0#state{connection_states = CS2, negotiated_version = Version, %% Requested version session = - Session0#session{session_id = Hello#client_hello.session_id, - is_resumable = false}, + Session0#session{session_id = Hello#client_hello.session_id}, tls_handshake_hashes = Hashes1}, {Record, State} = next_record(State1), next_state(hello, Record, State); @@ -706,9 +708,25 @@ connection(#hello_request{}, #state{host = Host, port = Port, ConnectionStates1, tls_handshake_hashes = Hashes1}), next_state(hello, Record, State); -connection(#client_hello{} = Hello, #state{role = server} = State) -> - hello(Hello, State); - +connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) -> + %% Mitigate Computational DoS attack http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html + %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client initiated renegotiation + %% we will disallow many client initiated renegotiations immediately after each other. + erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate), + hello(Hello, State#state{allow_renegotiate = false}); + +connection(#client_hello{}, #state{role = server, allow_renegotiate = false, + connection_states = ConnectionStates0, + socket = Socket, transport_cb = Transport, + negotiated_version = Version} = State0) -> + Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION), + {BinMsg, ConnectionStates} = + encode_alert(Alert, Version, ConnectionStates0), + Transport:send(Socket, BinMsg), + {Record, State} = next_record(State0#state{connection_states = + ConnectionStates}), + next_state(connection, Record, State); + connection(timeout, State) -> {next_state, connection, State, hibernate}; @@ -983,6 +1001,9 @@ handle_info({'DOWN', MonitorRef, _, _, _}, _, State = #state{user_application={MonitorRef,_Pid}}) -> {stop, normal, State}; +handle_info(allow_renegotiate, StateName, State) -> + {next_state, StateName, State#state{allow_renegotiate = true}, get_timeout(State)}; + handle_info(Msg, StateName, State) -> Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]), error_logger:info_report(Report), @@ -1126,18 +1147,38 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) -> {ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle), [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, PKey =:= 'RSAPrivateKey' orelse - PKey =:= 'DSAPrivateKey'], - public_key:pem_entry_decode(PemEntry, Password) + PKey =:= 'DSAPrivateKey' orelse + PKey =:= 'PrivateKeyInfo' + ], + private_key(public_key:pem_entry_decode(PemEntry, Password)) catch Error:Reason -> handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile, erlang:get_stacktrace()) end; +%% First two clauses are for backwards compatibility init_private_key(_,{rsa, PrivateKey}, _, _,_) -> - public_key:der_decode('RSAPrivateKey', PrivateKey); + init_private_key('RSAPrivateKey', PrivateKey); init_private_key(_,{dsa, PrivateKey},_,_,_) -> - public_key:der_decode('DSAPrivateKey', PrivateKey). + init_private_key('DSAPrivateKey', PrivateKey); +init_private_key(_,{Asn1Type, PrivateKey},_,_,_) -> + private_key(init_private_key(Asn1Type, PrivateKey)). + +init_private_key(Asn1Type, PrivateKey) -> + public_key:der_decode(Asn1Type, PrivateKey). + +private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = + #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'rsaEncryption'}, + privateKey = Key}) -> + public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)); + +private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = + #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'}, + privateKey = Key}) -> + public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); +private_key(Key) -> + Key. -spec(handle_file_error(_,_,_,_,_,_) -> no_return()). handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) -> @@ -1987,16 +2028,16 @@ next_state_is_connection(State0) -> public_key_info = undefined, tls_handshake_hashes = {<<>>, <<>>}}). -register_session(_, _, _, #session{is_resumable = true} = Session) -> - Session; %% Already registered -register_session(client, Host, Port, Session0) -> +register_session(client, Host, Port, #session{is_resumable = new} = Session0) -> Session = Session0#session{is_resumable = true}, ssl_manager:register_session(Host, Port, Session), Session; -register_session(server, _, Port, Session0) -> +register_session(server, _, Port, #session{is_resumable = new} = Session0) -> Session = Session0#session{is_resumable = true}, ssl_manager:register_session(Port, Session), - Session. + Session; +register_session(_, _, _, Session) -> + Session. %% Already registered invalidate_session(client, Host, Port, Session) -> ssl_manager:invalidate_session(Host, Port, Session); @@ -2020,7 +2061,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User, %% We do not want to save the password in the state so that %% could be written in the clear into error logs. ssl_options = SSLOptions#ssl_options{password = undefined}, - session = #session{is_resumable = false}, + session = #session{is_resumable = new}, transport_cb = CbModule, data_tag = DataTag, close_tag = CloseTag, @@ -2278,7 +2319,7 @@ renegotiate(#state{role = server, {Record, State} = next_record(State0#state{connection_states = ConnectionStates, tls_handshake_hashes = Hs0}), - next_state(hello, Record, State). + next_state(hello, Record, State#state{allow_renegotiate = true}). notify_senders(SendQueue) -> lists:foreach(fun({From, _}) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f873a6a913..7eb7f44df6 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1092,18 +1092,12 @@ certificate_authorities(CertDbHandle, CertDbRef) -> list_to_binary([Enc(Cert) || {_, Cert} <- Authorities]). certificate_authorities_from_db(CertDbHandle, CertDbRef) -> - certificate_authorities_from_db(CertDbHandle, CertDbRef, no_candidate, []). - -certificate_authorities_from_db(CertDbHandle,CertDbRef, PrevKey, Acc) -> - case ssl_manager:issuer_candidate(PrevKey, CertDbHandle) of - no_more_candidates -> - lists:reverse(Acc); - {{CertDbRef, _, _} = Key, Cert} -> - certificate_authorities_from_db(CertDbHandle, CertDbRef, Key, [Cert|Acc]); - {Key, _Cert} -> - %% skip certs not from this ssl connection - certificate_authorities_from_db(CertDbHandle, CertDbRef, Key, Acc) - end. + ConnectionCerts = fun({{Ref, _, _}, Cert}, Acc) when Ref == CertDbRef -> + [Cert | Acc]; + (_, Acc) -> + Acc + end, + ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle). digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index dcf310c535..6a44ef8c3e 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -29,8 +29,8 @@ %% Internal application API -export([start_link/1, start_link_dist/1, connection_init/2, cache_pem_file/2, - lookup_trusted_cert/4, issuer_candidate/2, client_session_id/4, - server_session_id/4, + lookup_trusted_cert/4, + client_session_id/4, server_session_id/4, register_session/2, register_session/3, invalidate_session/2, invalidate_session/3]). @@ -112,16 +112,7 @@ cache_pem_file(File, DbHandle) -> %% -------------------------------------------------------------------- lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer). -%%-------------------------------------------------------------------- --spec issuer_candidate(cert_key() | no_candidate, term()) -> - {cert_key(), - {der_cert(), - #'OTPCertificate'{}}} | no_more_candidates. -%% -%% Description: Return next issuer candidate. -%%-------------------------------------------------------------------- -issuer_candidate(PrevCandidateKey, DbHandle) -> - ssl_certificate_db:issuer_candidate(PrevCandidateKey, DbHandle). + %%-------------------------------------------------------------------- -spec client_session_id(host(), inet:port_number(), #ssl_options{}, der_cert() | undefined) -> session_id(). @@ -278,25 +269,16 @@ handle_cast({register_session, Port, Session}, CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession), {noreply, State}; -%%% When a session is invalidated we need to wait a while before deleting -%%% it as there might be pending connections that rightfully needs to look -%%% up the session data but new connections should not get to use this session. handle_cast({invalidate_session, Host, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> - CacheCb:update(Cache, {{Host, Port}, ID}, Session#session{is_resumable = false}), - TRef = - erlang:send_after(delay_time(), self(), {delayed_clean_session, {{Host, Port}, ID}}), - {noreply, State#state{last_delay_timer = TRef}}; + invalidate_session(Cache, CacheCb, {{Host, Port}, ID}, Session, State); handle_cast({invalidate_session, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> - CacheCb:update(Cache, {Port, ID}, Session#session{is_resumable = false}), - TRef = - erlang:send_after(delay_time(), self(), {delayed_clean_session, {Port, ID}}), - {noreply, State#state{last_delay_timer = TRef}}; + invalidate_session(Cache, CacheCb, {Port, ID}, Session, State); handle_cast({recache_pem, File, LastWrite, Pid, From}, #state{certificate_db = [_, FileToRefDb, _]} = State0) -> @@ -320,7 +302,7 @@ handle_cast({recache_pem, File, LastWrite, Pid, From}, %% {stop, reason(), #state{}}. %% %% Description: Handling all non call/cast messages -%%-------------------------------------------------------------------- +%%------------------------------------------------------------------- handle_info(validate_sessions, #state{session_cache_cb = CacheCb, session_cache = Cache, session_lifetime = LifeTime @@ -444,3 +426,20 @@ delay_time() -> _ -> ?CLEAN_SESSION_DB end. + +invalidate_session(Cache, CacheCb, Key, Session, State) -> + case CacheCb:lookup(Cache, Key) of + undefined -> %% Session is already invalidated + {noreply, State}; + #session{is_resumable = new} -> + CacheCb:delete(Cache, Key), + {noreply, State}; + _ -> + %% When a registered session is invalidated we need to wait a while before deleting + %% it as there might be pending connections that rightfully needs to look + %% up the session data but new connections should not get to use this session. + CacheCb:update(Cache, Key, Session#session{is_resumable = false}), + TRef = + erlang:send_after(delay_time(), self(), {delayed_clean_session, Key}), + {noreply, State#state{last_delay_timer = TRef}} + end. diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index bf738649f6..df5d7e0146 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -103,9 +103,9 @@ select_session([], _, _) -> select_session(Sessions, #ssl_options{ciphers = Ciphers, reuse_sessions = ReuseSession}, OwnCert) -> - IsResumable = - fun(Session) -> - ReuseSession andalso (Session#session.is_resumable) andalso + IsResumable = + fun(Session) -> + ReuseSession andalso resumable(Session#session.is_resumable) andalso lists:member(Session#session.cipher_suite, Ciphers) andalso (OwnCert == Session#session.own_certificate) end, @@ -147,10 +147,10 @@ is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache, #session{cipher_suite = CipherSuite, own_certificate = SessionOwnCert, compression_method = Compression, - is_resumable = Is_resumable, + is_resumable = IsResumable, peer_certificate = PeerCert} = Session -> ReuseEnabled - andalso Is_resumable + andalso resumable(IsResumable) andalso (OwnCert == SessionOwnCert) andalso valid_session(Session, SecondLifeTime) andalso ReuseFun(SuggestedSessionId, PeerCert, @@ -158,3 +158,8 @@ is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache, undefined -> false end. + +resumable(new) -> + false; +resumable(IsResumable) -> + IsResumable. diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 23a9a23190..6b1da63d08 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -39,6 +39,7 @@ MODULES = \ ssl_basic_SUITE \ ssl_handshake_SUITE \ ssl_packet_SUITE \ + ssl_cipher_SUITE \ ssl_payload_SUITE \ ssl_to_openssl_SUITE \ ssl_session_cache_SUITE \ @@ -55,6 +56,7 @@ HRL_FILES_SRC = \ ssl_internal.hrl\ ssl_alert.hrl \ ssl_handshake.hrl \ + ssl_cipher.hrl \ ssl_record.hrl HRL_FILES_INC = diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index a9109c5a6e..fc8aafa426 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -36,6 +36,7 @@ -define(LONG_TIMEOUT, 600000). -define(EXPIRE, 10). -define(SLEEP, 500). +-define(RENEGOTIATION_DISABLE_TIME, 12000). %% Test server callback functions %%-------------------------------------------------------------------- @@ -256,7 +257,7 @@ all() -> %%different_ca_peer_sign, no_reuses_session_server_restart_new_cert, no_reuses_session_server_restart_new_cert_file, reuseaddr, - hibernate, connect_twice + hibernate, connect_twice, renegotiate_dos_mitigate ]. groups() -> @@ -2592,7 +2593,7 @@ client_renegotiate(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {?MODULE, @@ -2784,7 +2785,7 @@ extended_key_usage_verify_peer(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), @@ -2846,7 +2847,7 @@ extended_key_usage_verify_none(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), @@ -2908,7 +2909,7 @@ no_authority_key_identifier(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), CertFile = proplists:get_value(certfile, ServerOpts), NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), @@ -2966,7 +2967,7 @@ invalid_signature_server(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "server/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), @@ -3006,7 +3007,7 @@ invalid_signature_client(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "client/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), ClientCertFile = proplists:get_value(certfile, ClientOpts), NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), @@ -3038,7 +3039,8 @@ tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> {Client, ClientMsg} -> ok; {Client, {error,closed}} -> - test_server:format("client got close"); + test_server:format("client got close"), + ok; Unexpected -> test_server:fail(Unexpected) end; @@ -3083,7 +3085,7 @@ cert_expired(Config) when is_list(Config) -> KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = public_key:pem_entry_decode(KeyEntry), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), @@ -3358,14 +3360,14 @@ der_input_opts(Opts) -> Keyfile = proplists:get_value(keyfile, Opts), Dhfile = proplists:get_value(dhfile, Opts), [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile), - [{_, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), + [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile), CaCerts = lists:map(fun(Entry) -> {_, CaCert, _} = Entry, CaCert end, ssl_test_lib:pem_to_der(CaCertsfile)), - {Cert, {rsa, Key}, CaCerts, DHParams}. + {Cert, {Asn1Type, Key}, CaCerts, DHParams}. %%-------------------------------------------------------------------- %% different_ca_peer_sign(doc) -> @@ -3588,14 +3590,13 @@ hibernate(Config) -> {from, self()}, {mfa, {?MODULE, send_recv_result_active, []}}, {options, [{hibernate_after, 1000}|ClientOpts]}]), - - { current_function, { _M, _F, _A } } = + {current_function, _} = process_info(Pid, current_function), timer:sleep(1100), - { current_function, { erlang, hibernate, 3} } = - process_info(Pid, current_function), + {current_function, {erlang, hibernate, 3}} = + process_info(Pid, current_function), ssl_test_lib:close(Server), ssl_test_lib:close(Client). @@ -3647,7 +3648,40 @@ connect_twice(Config) when is_list(Config) -> ssl_test_lib:close(Client), ssl_test_lib:close(Client1). +%%-------------------------------------------------------------------- +renegotiate_dos_mitigate(doc) -> + ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"]; + +renegotiate_dos_mitigate(suite) -> + []; + +renegotiate_dos_mitigate(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_immediately, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -3690,6 +3724,19 @@ renegotiate_reuse_session(Socket, Data) -> test_server:sleep(?SLEEP), renegotiate(Socket, Data). +renegotiate_immediately(Socket) -> + receive + {ssl, Socket, "Hello world"} -> + ok + end, + ok = ssl:renegotiate(Socket), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + test_server:sleep(?RENEGOTIATION_DISABLE_TIME +1), + ok = ssl:renegotiate(Socket), + test_server:format("Renegotiated again"), + ssl:send(Socket, "Hello world"), + ok. + new_config(PrivDir, ServerOpts0) -> CaCertFile = proplists:get_value(cacertfile, ServerOpts0), CertFile = proplists:get_value(certfile, ServerOpts0), diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl new file mode 100644 index 0000000000..99bc21e820 --- /dev/null +++ b/lib/ssl/test/ssl_cipher_SUITE.erl @@ -0,0 +1,163 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(ssl_cipher_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). +-include("ssl_cipher.hrl"). + +-define(TIMEOUT, 600000). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + try crypto:start() of + ok -> + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [aes_decipher_good, aes_decipher_fail]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%% Test cases starts here. +%%-------------------------------------------------------------------- +aes_decipher_good(doc) -> + ["Decipher a known cryptotext."]; + +aes_decipher_good(suite) -> + []; + +aes_decipher_good(Config) when is_list(Config) -> + HashSz = 32, + CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>, + key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>}, + Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8, + 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, + 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, + 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, + Version = {3,3}, + Content = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56,72,69,76,76,79,10>>, + Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>, + {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + ok. + +%%-------------------------------------------------------------------- + +aes_decipher_fail(doc) -> + ["Decipher a known cryptotext."]; + +aes_decipher_fail(suite) -> + []; + +%% same as above, last byte of key replaced +aes_decipher_fail(Config) when is_list(Config) -> + HashSz = 32, + CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>, + key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>}, + Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8, + 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, + 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, + 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, + Version = {3,3}, + {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + 32 = byte_size(Content), + 32 = byte_size(Mac), + ok. + +%%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 23e9268f9b..8fe55ee7a4 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -54,9 +54,14 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config0) -> try crypto:start() of ok -> - Config = add_ssl_opts_config(Config0), - setup_certs(Config), - Config + case test_server:is_cover() of + false -> + Config = add_ssl_opts_config(Config0), + setup_certs(Config), + Config; + true -> + {skip, "Can not be covered"} + end catch _:_ -> {skip, "Crypto did not start"} end. @@ -65,11 +70,31 @@ end_per_suite(Config) -> application:stop(crypto), Config. +init_per_testcase(plain_verify_options = Case, Config) when is_list(Config) -> + SslFlags = setup_dist_opts([{many_verify_opts, true} | Config]), + Flags = case os:getenv("ERL_FLAGS") of + false -> + os:putenv("ERL_FLAGS", SslFlags), + ""; + OldFlags -> + os:putenv("ERL_FLAGS", OldFlags ++ "" ++ SslFlags), + OldFlags + end, + common_init(Case, [{old_flags, Flags} | Config]); + init_per_testcase(Case, Config) when is_list(Config) -> + common_init(Case, Config). + +common_init(Case, Config) -> Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), [{watchdog, Dog},{testcase, Case}|Config]. -end_per_testcase(_Case, Config) when is_list(Config) -> +end_per_testcase(Case, Config) when is_list(Config) -> + Flags = proplists:get_value(old_flags, Config), + os:putenv("ERL_FLAGS", Flags), + common_end(Case, Config). + +common_end(_, Config) -> Dog = ?config(watchdog, Config), ?t:timetrap_cancel(Dog), ok. @@ -205,9 +230,9 @@ plain_verify_options(Config) when is_list(Config) -> "server_reuse_sessions true client_reuse_sessions true " "server_hibernate_after 500 client_hibernate_after 500", - NH1 = start_ssl_node([{additional_dist_opts, DistOpts}, {many_verify_opts, true} | Config]), + NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]), Node1 = NH1#node_handle.nodename, - NH2 = start_ssl_node([{additional_dist_opts, DistOpts}, {many_verify_opts, true} | Config]), + NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]), Node2 = NH2#node_handle.nodename, pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), @@ -467,8 +492,10 @@ cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) -> ets:insert(test_server_info, {test_server_handler, self()}), ssl_node_con_loop(Socket); - _Error -> - halt("Failed to connect to test server") + Error -> + halt("Failed to connect to test server " ++ + lists:flatten(io_lib:format("Host:~p ~n Port:~p~n Error:~p~n", + [Host, Port, Error]))) end end), spawn(fun () -> @@ -476,9 +503,8 @@ cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) -> receive {'DOWN', Mon, process, ConnHandler, Reason} -> receive after 1000 -> ok end, - halt("test server connection handler terminated: " - ++ - lists:flatten(io_lib:format("~p", [Reason]))) + halt("test server connection handler terminated: " ++ + lists:flatten(io_lib:format("~p", [Reason]))) end end). @@ -613,19 +639,34 @@ setup_dist_opts(Config) -> ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " "; true -> - "-proto_dist inet_tls " - ++ "-ssl_dist_opt server_certfile " ++ SC ++ " " - ++ "-ssl_dist_opt server_keyfile " ++ SK ++ " " - ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " " - ++ "-ssl_dist_opt server_verify verify_peer " - ++ "-ssl_dist_opt server_fail_if_no_peer_cert true " - ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA " - ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " " - ++ "-ssl_dist_opt client_certfile " ++ CC ++ " " - ++ "-ssl_dist_opt client_keyfile " ++ CK ++ " " - ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " " - ++ "-ssl_dist_opt client_verify verify_peer " - ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA " + case os:type() of + {win32, _} -> + "-proto_dist inet_tls " + ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " + ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " " + ++ "-ssl_dist_opt server_verify verify_peer " + ++ "-ssl_dist_opt server_fail_if_no_peer_cert true " + ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA " + ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " " + ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " " + ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " " + ++ "-ssl_dist_opt client_verify verify_peer " + ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA "; + _ -> + "-proto_dist inet_tls " + ++ "-ssl_dist_opt server_certfile " ++ SC ++ " " + ++ "-ssl_dist_opt server_keyfile " ++ SK ++ " " + ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " " + ++ "-ssl_dist_opt server_verify verify_peer " + ++ "-ssl_dist_opt server_fail_if_no_peer_cert true " + ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA " + ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " " + ++ "-ssl_dist_opt client_certfile " ++ CC ++ " " + ++ "-ssl_dist_opt client_keyfile " ++ CK ++ " " + ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " " + ++ "-ssl_dist_opt client_verify verify_peer " + ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA " + end end, MoreOpts = proplists:get_value(additional_dist_opts, Config, []), DistOpts ++ MoreOpts. diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 5ea45018e6..8cdfdec2ce 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -229,7 +229,7 @@ session_cleanup(Config)when is_list(Config) -> check_timer(DelayTimer), - test_server:sleep(?SLEEP), %% Make sure clean has had to run + test_server:sleep(?SLEEP), %% Make sure clean has had time to run undefined = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}), undefined = ssl_session_cache:lookup(Cache, {Port, Id}), diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index b7916b96eb..46a8112a41 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -22,6 +22,7 @@ -include("test_server.hrl"). -include("test_server_line.hrl"). +-include_lib("public_key/include/public_key.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -673,3 +674,16 @@ cipher_result(Socket, Result) -> session_info_result(Socket) -> ssl:session_info(Socket). + + +public_key(#'PrivateKeyInfo'{privateKeyAlgorithm = + #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption}, + privateKey = Key}) -> + public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)); + +public_key(#'PrivateKeyInfo'{privateKeyAlgorithm = + #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'}, + privateKey = Key}) -> + public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); +public_key(Key) -> + Key. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 64a6a9eaf8..f37baeb9de 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -109,6 +109,9 @@ special_init(TestCase, Config) TestCase == erlang_server_openssl_client_no_wrap_sequence_number -> check_sane_openssl_renegotaite(Config); +special_init(ssl2_erlang_server_openssl_client, Config) -> + check_sane_openssl_sslv2(Config); + special_init(_, Config) -> Config. @@ -168,7 +171,8 @@ all() -> tls1_erlang_server_openssl_client_client_cert, tls1_erlang_server_erlang_client_client_cert, ciphers_rsa_signed_certs, ciphers_dsa_signed_certs, - erlang_client_bad_openssl_server, expired_session, + erlang_client_bad_openssl_server, + expired_session, ssl2_erlang_server_openssl_client]. groups() -> @@ -222,7 +226,6 @@ erlang_client_openssl_server(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -256,9 +259,9 @@ erlang_server_openssl_client(Config) when is_list(Config) -> port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), - - ssl_test_lib:close(Server), + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close(Server), close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -306,7 +309,6 @@ tls1_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -346,8 +348,8 @@ tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -395,7 +397,6 @@ ssl3_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -435,8 +436,8 @@ ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -475,8 +476,8 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -525,7 +526,6 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -574,7 +574,6 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -615,8 +614,8 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config ssl_test_lib:check_result(Server, ok), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -663,7 +662,6 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -674,6 +672,7 @@ ssl3_erlang_client_openssl_server(doc) -> ssl3_erlang_client_openssl_server(suite) -> []; ssl3_erlang_client_openssl_server(Config) when is_list(Config) -> + process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -700,11 +699,11 @@ ssl3_erlang_client_openssl_server(Config) when is_list(Config) -> {options, [{versions, [sslv3]} | ClientOpts]}]), ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Client), - %% Clean close down! + + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), - test_server:sleep(?SLEEP), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- @@ -714,6 +713,7 @@ ssl3_erlang_server_openssl_client(doc) -> ssl3_erlang_server_openssl_client(suite) -> []; ssl3_erlang_server_openssl_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), {_, ServerNode, _} = ssl_test_lib:run_where(Config), @@ -734,10 +734,10 @@ ssl3_erlang_server_openssl_client(Config) when is_list(Config) -> OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), ssl_test_lib:check_result(Server, ok), - - close_port(OpenSslPort), %% openssl server first + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - test_server:sleep(?SLEEP), + close_port(OpenSslPort), + process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- @@ -779,7 +779,7 @@ ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), - %% Clean close down! + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false), @@ -824,9 +824,9 @@ ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), - close_port(OpenSslPort), %% openssl server first + %% Clean close down! Server needs to be closed first !! + close_port(OpenSslPort), ssl_test_lib:close(Server), - %% Clean close down! process_flag(trap_exit, false), ok. @@ -907,10 +907,10 @@ tls1_erlang_client_openssl_server(Config) when is_list(Config) -> [{versions, [tlsv1]} | ClientOpts]}]), ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Client), - %% Clean close down! + + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), + ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -943,9 +943,9 @@ tls1_erlang_server_openssl_client(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), - %% Clean close down! - close_port(OpenSslPort), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), + close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -989,7 +989,7 @@ tls1_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), - %% Clean close down! + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false), @@ -1034,9 +1034,9 @@ tls1_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), - %% Clean close down! - close_port(OpenSslPort), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), + close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -1071,9 +1071,7 @@ tls1_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> [{versions, [tlsv1]} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - %% Clean close down! process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- @@ -1136,7 +1134,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -1171,8 +1169,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> Result = ssl_test_lib:wait_for_result(Client, ok), + %% Clean close down! Server needs to be closed first !! close_port(OpenSslPort), - %% Clean close down! ssl_test_lib:close(Client), Return = case Result of @@ -1184,6 +1182,12 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, false), Return. + +version_flag(tlsv1) -> + " -tls1 "; +version_flag(sslv3) -> + " -ssl3 ". + %%-------------------------------------------------------------------- erlang_client_bad_openssl_server(doc) -> [""]; @@ -1199,26 +1203,26 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - + " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", + test_server:format("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - + wait_for_openssl_server(), Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, server_sent_garbage, []}}, - {options, - [{versions, [tlsv1]} | ClientOpts]}]), + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, server_sent_garbage, []}}, + {options, + [{versions, [tlsv1]} | ClientOpts]}]), %% Send garbage port_command(OpensslPort, ?OPENSSL_GARBAGE), - + test_server:sleep(?SLEEP), Client0 ! server_sent_garbage, @@ -1228,17 +1232,16 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> ssl_test_lib:close(Client0), %% Make sure openssl does not hang and leave zombie process - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result_msg, []}}, - {options, - [{versions, [tlsv1]} | ClientOpts]}]), - - ssl_test_lib:close(Client1), - - %% Clean close down! + Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result_msg, []}}, + {options, + [{versions, [tlsv1]} | ClientOpts]}]), + + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), + ssl_test_lib:close(Client1), process_flag(trap_exit, false), ok. @@ -1297,6 +1300,7 @@ expired_session(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {from, self()}, {options, ClientOpts}]), + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client2), process_flag(trap_exit, false). @@ -1329,8 +1333,8 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, {error,"protocol version"}), + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -1433,3 +1437,11 @@ check_sane_openssl_renegotaite(Config) -> _ -> Config end. + +check_sane_openssl_sslv2(Config) -> + case os:cmd("openssl version") of + "OpenSSL 1.0.0e" ++ _ -> + {skip, "Known option bug"}; + _ -> + Config + end. diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 8286201df4..2255798f1d 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 4.1.6 +SSL_VSN = 5.0 diff --git a/lib/stdlib/doc/src/make.dep b/lib/stdlib/doc/src/make.dep deleted file mode 100644 index 48ee6209ef..0000000000 --- a/lib/stdlib/doc/src/make.dep +++ /dev/null @@ -1,40 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: array.tex base64.tex beam_lib.tex book.tex \ - c.tex calendar.tex dets.tex dict.tex digraph.tex \ - digraph_utils.tex epp.tex erl_eval.tex erl_expand_records.tex \ - erl_id_trans.tex erl_internal.tex erl_lint.tex \ - erl_parse.tex erl_pp.tex erl_scan.tex erl_tar.tex \ - ets.tex file_sorter.tex filelib.tex filename.tex \ - gb_sets.tex gb_trees.tex gen_event.tex gen_fsm.tex \ - gen_server.tex io.tex io_lib.tex io_protocol.tex \ - lib.tex lists.tex log_mf_h.tex math.tex ms_transform.tex \ - orddict.tex ordsets.tex part.tex pg.tex pool.tex \ - proc_lib.tex proplists.tex qlc.tex queue.tex \ - random.tex re.tex ref_man.tex regexp.tex sets.tex \ - shell.tex shell_default.tex slave.tex sofs.tex \ - stdlib_app.tex string.tex supervisor.tex supervisor_bridge.tex \ - sys.tex timer.tex unicode.tex unicode_usage.tex \ - win32reg.tex zip.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: ushell1.ps - diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 30514dfee9..cddb55e5c5 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -158,7 +158,7 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} death causes the temporary process to be terminated) and a <c>transient</c> child process should be restarted only if it terminates abnormally, i.e. with another exit reason - than <c>normal</c>.</p> + than <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</p> </item> <item> <p><c>Shutdown</c> defines how a child process should be @@ -355,14 +355,23 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <desc> <p>Tells the supervisor <c><anno>SupRef</anno></c> to terminate the given child.</p> + <p>If the supervisor is not <c>simple_one_for_one</c>, - <c><anno>Id</anno></c> must be the child specification identifier. The - process, if there is one, is terminated but the child - specification is kept by the supervisor. The child process - may later be restarted by the supervisor. The child process - can also be restarted explicitly by calling + <c><anno>Id</anno></c> must be the child specification + identifier. The process, if there is one, is terminated and, + unless it is a temporary child, the child specification is + kept by the supervisor. The child process may later be + restarted by the supervisor. The child process can also be + restarted explicitly by calling <c>restart_child/2</c>. Use <c>delete_child/2</c> to remove the child specification.</p> + + <p>If the child is temporary, the child specification is deleted as + soon as the process terminates. This means + that <c>delete_child/2</c> has no meaning + and <c>restart_child/2</c> can not be used for these + children.</p> + <p>If the supervisor is <c>simple_one_for_one</c>, <c><anno>Id</anno></c> must be the child process' <c>pid()</c>. I the specified process is alive, but is not a child of the given @@ -399,26 +408,34 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <name name="restart_child" arity="2"/> <fsummary>Restart a terminated child process belonging to a supervisor.</fsummary> <desc> - <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart a child process - corresponding to the child specification identified by - <c><anno>Id</anno></c>. The child specification must exist and - the corresponding child process must not be running.</p> - <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso> for a description of - <c>SupRef</c>.</p> - <p>If the child specification identified by <c><anno>Id</anno></c> does not - exist, the function returns <c>{error,not_found}</c>. If - the child specification exists but the corresponding process - is already running, the function returns + <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart + a child process corresponding to the child specification + identified by <c><anno>Id</anno></c>. The child + specification must exist and the corresponding child process + must not be running.</p> + <p>Note that for temporary children, the child specification + is automatically deleted when the child terminates, and thus + it is not possible to restart such children.</p> + <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso> + for a description of <c>SupRef</c>.</p> + <p>If the child specification identified + by <c><anno>Id</anno></c> does not exist, the function + returns <c>{error,not_found}</c>. If the child specification + exists but the corresponding process is already running, the + function returns <c>{error,running}</c>.</p> - <p>If the child process start function returns <c>{ok,<anno>Child</anno>}</c> - or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid is added to the supervisor - and the function returns the same value.</p> + <p>If the child process start function + returns <c>{ok,<anno>Child</anno>}</c> + or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid + is added to the supervisor and the function returns the same + value.</p> <p>If the child process start function returns <c>ignore</c>, the pid remains set to <c>undefined</c> and the function returns <c>{ok,undefined}</c>.</p> - <p>If the child process start function returns an error tuple or - an erroneous value, or if it fails, the function returns - <c>{error,<anno>Error</anno>}</c> where <c><anno>Error</anno></c> is a term containing + <p>If the child process start function returns an error tuple + or an erroneous value, or if it fails, the function returns + <c>{error,<anno>Error</anno>}</c> + where <c><anno>Error</anno></c> is a term containing information about the error.</p> </desc> </func> diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index b63acdd40a..72e41d6473 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -419,7 +419,14 @@ expr({'fun',Line,Body}) -> {'fun',Line,{clauses,Cs1}}; {function,F,A} -> {'fun',Line,{function,F,A}}; - {function,M,F,A} -> %R10B-6: fun M:F/A. + {function,M,F,A} when is_atom(M), is_atom(F), is_integer(A) -> + %% R10B-6: fun M:F/A. (Backward compatibility) + {'fun',Line,{function,M,F,A}}; + {function,M0,F0,A0} -> + %% R15: fun M:F/A with variables. + M = expr(M0), + F = expr(F0), + A = expr(A0), {'fun',Line,{function,M,F,A}} end; expr({call,Line,F0,As0}) -> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 4f4fa16040..88a0094d57 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -256,7 +256,8 @@ expr({'receive',_,Cs}, Bs, Lf, Ef, RBs) -> expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs) -> {value,T,Bs} = expr(E, Bs0, Lf, Ef, none), receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, [], RBs); -expr({'fun',_Line,{function,Mod,Name,Arity}}, Bs, _Lf, _Ef, RBs) -> +expr({'fun',_Line,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) -> + {[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef), F = erlang:make_fun(Mod, Name, Arity), ret_expr(F, Bs, RBs); expr({'fun',_Line,{function,Name,Arity}}, _Bs0, _Lf, _Ef, _RBs) -> % R8 diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 78b996d94b..5d45260fe9 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2127,8 +2127,13 @@ expr({'fun',Line,Body}, Vt, St) -> true -> {[],St}; false -> {[],call_function(Line, F, A, St)} end; - {function,_M,_F,_A} -> - {[],St} + {function,M,F,A} when is_atom(M), is_atom(F), is_integer(A) -> + %% Compatibility with pre-R15 abstract format. + {[],St}; + {function,M,F,A} -> + %% New in R15. + {Bvt, St1} = expr_list([M,F,A], Vt, St), + {vtupdate(Bvt, Vt),St1} end; expr({call,_Line,{atom,_Lr,is_record},[E,{atom,Ln,Name}]}, Vt, St0) -> {Rvt,St1} = expr(E, Vt, St0), diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 709bd83e6f..928c10f7f2 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -35,7 +35,7 @@ tuple %struct record_expr record_tuple record_field record_fields if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr -fun_expr fun_clause fun_clauses +fun_expr fun_clause fun_clauses atom_or_var integer_or_var try_expr try_catch try_clause try_clauses query_expr function_call argument_list exprs guard @@ -395,11 +395,17 @@ receive_expr -> 'receive' cr_clauses 'after' expr clause_body 'end' : fun_expr -> 'fun' atom '/' integer : {'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4')}}. -fun_expr -> 'fun' atom ':' atom '/' integer : - {'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4'),element(3,'$6')}}. +fun_expr -> 'fun' atom_or_var ':' atom_or_var '/' integer_or_var : + {'fun',?line('$1'),{function,'$2','$4','$6'}}. fun_expr -> 'fun' fun_clauses 'end' : build_fun(?line('$1'), '$2'). +atom_or_var -> atom : '$1'. +atom_or_var -> var : '$1'. + +integer_or_var -> integer : '$1'. +integer_or_var -> var : '$1'. + fun_clauses -> fun_clause : ['$1']. fun_clauses -> fun_clause ';' fun_clauses : ['$1' | '$3']. diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index 7dc19f2e9b..6b5aa951cf 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -457,8 +457,16 @@ lexpr({'fun',_,{function,F,A}}, _Prec, _Hook) -> leaf(format("fun ~w/~w", [F,A])); lexpr({'fun',_,{function,F,A},Extra}, _Prec, _Hook) -> {force_nl,fun_info(Extra),leaf(format("fun ~w/~w", [F,A]))}; -lexpr({'fun',_,{function,M,F,A}}, _Prec, _Hook) -> +lexpr({'fun',_,{function,M,F,A}}, _Prec, _Hook) + when is_atom(M), is_atom(F), is_integer(A) -> + %% For backward compatibility with pre-R15 abstract format. leaf(format("fun ~w:~w/~w", [M,F,A])); +lexpr({'fun',_,{function,M,F,A}}, _Prec, Hook) -> + %% New format in R15. + NameItem = lexpr(M, Hook), + CallItem = lexpr(F, Hook), + ArityItem = lexpr(A, Hook), + ["fun ",NameItem,$:,CallItem,$/,ArityItem]; lexpr({'fun',_,{clauses,Cs}}, _Prec, Hook) -> {list,[{first,'fun',fun_clauses(Cs, Hook)},'end']}; lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Hook) -> diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl index 1cb9e4a25e..2fc9128e4e 100644 --- a/lib/stdlib/src/filename.erl +++ b/lib/stdlib/src/filename.erl @@ -147,9 +147,10 @@ basename(Name) when is_binary(Name) -> end; basename(Name0) -> - Name = flatten(Name0), + Name1 = flatten(Name0), {DirSep2, DrvSep} = separators(), - basename1(skip_prefix(Name, DrvSep), [], DirSep2). + Name = skip_prefix(Name1, DrvSep), + basename1(Name, Name, DirSep2). win_basenameb(<<Letter,$:,Rest/binary>>) when ?IS_DRIVELETTER(Letter) -> basenameb(Rest,[<<"/">>,<<"\\">>]); @@ -167,16 +168,18 @@ basenameb(Bin,Sep) -> -basename1([$/|[]], Tail, DirSep2) -> - basename1([], Tail, DirSep2); +basename1([$/], Tail0, _DirSep2) -> + %% End of filename -- must get rid of trailing directory separator. + [_|Tail] = lists:reverse(Tail0), + lists:reverse(Tail); basename1([$/|Rest], _Tail, DirSep2) -> - basename1(Rest, [], DirSep2); + basename1(Rest, Rest, DirSep2); basename1([DirSep2|Rest], Tail, DirSep2) when is_integer(DirSep2) -> basename1([$/|Rest], Tail, DirSep2); basename1([Char|Rest], Tail, DirSep2) when is_integer(Char) -> - basename1(Rest, [Char|Tail], DirSep2); + basename1(Rest, Tail, DirSep2); basename1([], Tail, _DirSep2) -> - lists:reverse(Tail). + Tail. skip_prefix(Name, false) -> Name; @@ -369,8 +372,8 @@ extension(Name0) -> Name = flatten(Name0), extension(Name, [], major_os_type()). -extension([$.|Rest], _Result, OsType) -> - extension(Rest, [$.], OsType); +extension([$.|Rest]=Result, _Result, OsType) -> + extension(Rest, Result, OsType); extension([Char|Rest], [], OsType) when is_integer(Char) -> extension(Rest, [], OsType); extension([$/|Rest], _Result, OsType) -> @@ -378,9 +381,9 @@ extension([$/|Rest], _Result, OsType) -> extension([$\\|Rest], _Result, win32) -> extension(Rest, [], win32); extension([Char|Rest], Result, OsType) when is_integer(Char) -> - extension(Rest, [Char|Result], OsType); + extension(Rest, Result, OsType); extension([], Result, _OsType) -> - lists:reverse(Result). + Result. %% Joins a list of filenames with directory separators. diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 574146b1cd..5d803091b6 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -273,7 +273,7 @@ reply({To, Tag}, Reply) -> %%%----------------------------------------------------------------- %%% Misc. functions. %%%----------------------------------------------------------------- -where({global, Name}) -> global:safe_whereis_name(Name); +where({global, Name}) -> global:whereis_name(Name); where({local, Name}) -> whereis(Name). name_register({local, Name} = LN) -> diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index 3db8c9f4f2..57734a075c 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -296,7 +296,7 @@ get_proc_name({local, Name}) -> exit(process_not_registered) end; get_proc_name({global, Name}) -> - case global:safe_whereis_name(Name) of + case global:whereis_name(Name) of undefined -> exit(process_not_registered_globally); Pid when Pid =:= self() -> @@ -318,7 +318,7 @@ get_parent() -> name_to_pid(Name) -> case whereis(Name) of undefined -> - case global:safe_whereis_name(Name) of + case global:whereis_name(Name) of undefined -> exit(could_not_find_registerd_name); Pid -> @@ -348,12 +348,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) -> proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug); {stop, Reason} -> + unregister_name(Name0), proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); ignore -> + unregister_name(Name0), proc_lib:init_ack(Starter, ignore), exit(normal); {'EXIT', Reason} -> + unregister_name(Name0), proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); Else -> @@ -366,6 +369,13 @@ name({local,Name}) -> Name; name({global,Name}) -> Name; name(Pid) when is_pid(Pid) -> Pid. +unregister_name({local,Name}) -> + _ = (catch unregister(Name)); +unregister_name({global,Name}) -> + _ = global:unregister_name(Name); +unregister_name(Pid) when is_pid(Pid) -> + Pid. + %%----------------------------------------------------------------- %% The MAIN loop %%----------------------------------------------------------------- diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index dd0ef74f30..6f075bbe5a 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -820,7 +820,7 @@ get_proc_name({local, Name}) -> exit(process_not_registered) end; get_proc_name({global, Name}) -> - case global:safe_whereis_name(Name) of + case global:whereis_name(Name) of undefined -> exit(process_not_registered_globally); Pid when Pid =:= self() -> @@ -842,7 +842,7 @@ get_parent() -> name_to_pid(Name) -> case whereis(Name) of undefined -> - case global:safe_whereis_name(Name) of + case global:whereis_name(Name) of undefined -> exit(could_not_find_registerd_name); Pid -> diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index f5e180b4bd..2b691e6abf 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.erl @@ -1272,7 +1272,10 @@ abstr_term(Fun, Line) when is_function(Fun) -> case erlang:fun_info(Fun, type) of {type, external} -> {module, Module} = erlang:fun_info(Fun, module), - {'fun', Line, {function,Module,Name,Arity}}; + {'fun', Line, {function, + {atom,Line,Module}, + {atom,Line,Name}, + {integer,Line,Arity}}}; {type, local} -> {'fun', Line, {function,Name,Arity}} end diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index 99bcbd722e..246d535943 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -48,7 +48,7 @@ split(Subject,RE) -> Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata() | unicode:charlist(), Options :: [ Option ], - Option :: anchored | global | notbol | noteol | notempty + Option :: anchored | notbol | noteol | notempty | {offset, non_neg_integer()} | {newline, nl_spec()} | bsr_anycrlf | bsr_unicode | {return, ReturnType} | {parts, NumParts} | group | trim | CompileOpt, diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 54a63833e6..94e81188b5 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -1 +1,27 @@ -{"%VSN%",[],[]}. +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{"%VSN%", + %% Up from - max two major revisions back + [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + %% Down to - max two major revisions back + [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 +}. diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index f20ea18fd0..2dd5ccce7a 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -1238,15 +1238,15 @@ report_error(Error, Reason, Child, SupName) -> error_logger:error_report(supervisor_report, ErrorMsg). -extract_child(Child) when is_pid(Child#child.pid) -> - [{pid, Child#child.pid}, +extract_child(Child) when is_list(Child#child.pid) -> + [{nb_children, length(Child#child.pid)}, {name, Child#child.name}, {mfargs, Child#child.mfargs}, {restart_type, Child#child.restart_type}, {shutdown, Child#child.shutdown}, {child_type, Child#child.child_type}]; extract_child(Child) -> - [{nb_children, length(Child#child.pid)}, + [{pid, Child#child.pid}, {name, Child#child.name}, {mfargs, Child#child.mfargs}, {restart_type, Child#child.restart_type}, diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index 8fb63f33bd..bac59a3107 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -20,7 +20,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - interesting/1,random_ref_comp/1,random_ref_sr_comp/1, + interesting/1,scope_return/1,random_ref_comp/1,random_ref_sr_comp/1, random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1, copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]). @@ -67,7 +67,7 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [interesting, random_ref_fla_comp, random_ref_sr_comp, + [scope_return,interesting, random_ref_fla_comp, random_ref_sr_comp, random_ref_comp, parts, bin_to_list, list_to_bin, copy, referenced, guard, encode_decode, badargs, longest_common_trap]. @@ -379,6 +379,20 @@ subj() -> Subject. +scope_return(doc) -> + ["Test correct return values for scopes (OTP-9701)."]; +scope_return(Config) when is_list(Config) -> + N=10000, + Bin=binary:copy(<<"a">>,N), + scope_loop(Bin,0,N). + +scope_loop(_,N,N) -> + ok; +scope_loop(Bin,N,M) -> + ?line {N,1} = binary:match(Bin,<<"a">>,[{scope,{N,1}}]), + ?line {N,1} = binary:match(Bin,[<<"a">>,<<"b">>],[{scope,{N,1}}]), + scope_loop(Bin,N+1,M). + interesting(doc) -> ["Try some interesting patterns"]; interesting(Config) when is_list(Config) -> diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 784c7cb86e..369d8b224e 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1036,6 +1036,12 @@ funs(Config) when is_list(Config) -> lists:usort([run_many_args(SAs) || SAs <- many_args(MaxArgs)]), ?line {'EXIT',{{argument_limit,_},_}} = (catch run_many_args(many_args1(MaxArgs+1))), + + ?line check(fun() -> M = lists, F = fun M:reverse/1, + [1,2] = F([2,1]), ok end, + "begin M = lists, F = fun M:reverse/1," + " [1,2] = F([2,1]), ok end.", + ok), ok. run_many_args({S, As}) -> diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 280c95b1aa..64853ca078 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -116,7 +116,6 @@ func(Config) when is_list(Config) -> {func_3, <<"t() -> fun t/0.">>}, {func_4, - %% Has already been expanded away in sys_pre_expand. <<"t() -> fun modul:foo/3.">>}, {func_5, % 'when' is moved down one line <<"tkjlksjflksdjflsdjlk() @@ -127,7 +126,9 @@ func(Config) when is_list(Config) -> <<"t() -> (fun() -> true - end)().">>} + end)().">>}, + {func_7, + <<"t(M, F, A) -> fun M:F/A.">>} ], ?line compile(Config, Ts), ok. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 2f4958760b..0e8849b5b3 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -74,7 +74,7 @@ -export([bad_table/1, types/1]). -export([otp_9423/1]). --export([init_per_testcase/2, end_per_testcase/2]). +-export([init_per_testcase/2]). %% Convenience for manual testing -export([random_test/0]). @@ -176,6 +176,7 @@ groups() -> meta_newdel_unnamed, meta_newdel_named]}]. init_per_suite(Config) -> + erts_debug:set_internal_state(available_internal_state, true), Config. end_per_suite(_Config) -> @@ -304,7 +305,6 @@ t_match_spec_run(Config) when is_list(Config) -> end, repeat_for_permutations(F, N_MS) end, - test_terms(Fun, skip_refc_check), ?line verify_etsmem(EtsMem). @@ -324,7 +324,7 @@ t_match_spec_run_test(List, MS, Result) -> %% Check that tracing agree Self = self(), - {Tracee, MonRef} = spawn_monitor(fun() -> ms_tracee(Self, List) end), + {Tracee, MonRef} = my_spawn_monitor(fun() -> ms_tracee(Self, List) end), receive {Tracee, ready} -> ok end, MST = lists:map(fun(Clause) -> ms_clause_ets_to_trace(Clause) end, MS), @@ -585,7 +585,6 @@ select_fail_do(Opts) -> memory(doc) -> ["Whitebox test of ets:info(X,memory)"]; memory(suite) -> []; memory(Config) when is_list(Config) -> - ?line erts_debug:set_internal_state(available_internal_state, true), ?line ok = chk_normal_tab_struct_size(), repeat_for_opts(memory_do,[compressed]), ?line catch erts_debug:set_internal_state(available_internal_state, false). @@ -1947,7 +1946,7 @@ evil_update_counter(Config) when is_list(Config) -> evil_update_counter_do(Opts) -> ?line EtsMem = etsmem(), ?line process_flag(trap_exit, true), - ?line Pids = [spawn_link(fun() -> evil_counter(I,Opts) end) || I <- lists:seq(1, 40)], + ?line Pids = [my_spawn_link(fun() -> evil_counter(I,Opts) end) || I <- lists:seq(1, 40)], ?line wait_for_all(gb_sets:from_list(Pids)), ?line verify_etsmem(EtsMem), ok. @@ -2153,24 +2152,24 @@ heir_do(Opts) -> Combos), %% No heir - {Founder1,MrefF1} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end), + {Founder1,MrefF1} = my_spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end), Founder1 ! {go, none}, ?line {"No heir",Founder1} = receive_any(), ?line {'DOWN', MrefF1, process, Founder1, normal} = receive_any(), ?line undefined = ets:info(foo), %% An already dead heir - {Heir2,MrefH2} = spawn_monitor(fun()->die end), + {Heir2,MrefH2} = my_spawn_monitor(fun()->die end), ?line {'DOWN', MrefH2, process, Heir2, normal} = receive_any(), - {Founder2,MrefF2} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end), + {Founder2,MrefF2} = my_spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end), Founder2 ! {go, Heir2}, ?line {"No heir",Founder2} = receive_any(), ?line {'DOWN', MrefF2, process, Founder2, normal} = receive_any(), ?line undefined = ets:info(foo), %% When heir dies before founder - {Founder3,MrefF3} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end), - {Heir3,MrefH3} = spawn_monitor(fun()->heir_heir(Founder3)end), + {Founder3,MrefF3} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end), + {Heir3,MrefH3} = my_spawn_monitor(fun()->heir_heir(Founder3)end), Founder3 ! {go, Heir3}, ?line {'DOWN', MrefH3, process, Heir3, normal} = receive_any(), Founder3 ! die_please, @@ -2178,14 +2177,12 @@ heir_do(Opts) -> ?line undefined = ets:info(foo), %% When heir dies and pid reused before founder dies - erts_debug:set_internal_state(available_internal_state,true), NextPidIx = erts_debug:get_internal_state(next_pid), - {Founder4,MrefF4} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end), - {Heir4,MrefH4} = spawn_monitor(fun()->heir_heir(Founder4)end), + {Founder4,MrefF4} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end), + {Heir4,MrefH4} = my_spawn_monitor(fun()->heir_heir(Founder4)end), Founder4 ! {go, Heir4}, ?line {'DOWN', MrefH4, process, Heir4, normal} = receive_any(), erts_debug:set_internal_state(next_pid, NextPidIx), - erts_debug:set_internal_state(available_internal_state,false), {Heir4,MrefH4_B} = spawn_monitor_with_pid(Heir4, fun()-> ?line die_please = receive_any() end), Founder4 ! die_please, @@ -2261,9 +2258,9 @@ heir_heir(Founder, Mode) -> heir_1(HeirData,Mode,Opts) -> io:format("test with heir_data = ~p\n", [HeirData]), Master = self(), - ?line Founder = spawn_link(fun() -> heir_founder(Master,HeirData,Opts) end), + ?line Founder = my_spawn_link(fun() -> heir_founder(Master,HeirData,Opts) end), io:format("founder spawned = ~p\n", [Founder]), - ?line {Heir,Mref} = spawn_monitor(fun() -> heir_heir(Founder,Mode) end), + ?line {Heir,Mref} = my_spawn_monitor(fun() -> heir_heir(Founder,Mode) end), io:format("heir spawned = ~p\n", [{Heir,Mref}]), ?line Founder ! {go, Heir}, ?line {'DOWN', Mref, process, Heir, normal} = receive_any(). @@ -2280,7 +2277,7 @@ give_away_do(Opts) -> Parent = self(), %% Give and then give back - ?line {Receiver,Mref} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end), + ?line {Receiver,Mref} = my_spawn_monitor(fun()-> give_away_receiver(T,Parent) end), ?line give_me = receive_any(), ?line true = ets:give_away(T,Receiver,here_you_are), ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)), @@ -2291,7 +2288,7 @@ give_away_do(Opts) -> %% Give and then let receiver keep it ?line true = ets:insert(T,{key,1}), - ?line {Receiver3,Mref3} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end), + ?line {Receiver3,Mref3} = my_spawn_monitor(fun()-> give_away_receiver(T,Parent) end), ?line give_me = receive_any(), ?line true = ets:give_away(T,Receiver3,here_you_are), ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)), @@ -2303,7 +2300,7 @@ give_away_do(Opts) -> ?line T2 = ets_new(foo,[private | Opts]), ?line true = ets:insert(T2,{key,1}), ?line ets:setopts(T2,{heir,self(),"Som en gummiboll..."}), - ?line {Receiver2,Mref2} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end), + ?line {Receiver2,Mref2} = my_spawn_monitor(fun()-> give_away_receiver(T2,Parent) end), ?line give_me = receive_any(), ?line true = ets:give_away(T2,Receiver2,here_you_are), ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T2,key)), @@ -2318,12 +2315,12 @@ give_away_do(Opts) -> ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,"not a pid","To wrong type")), ?line true = ets:delete(T2), - ?line {ReceiverNeg,MrefNeg} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end), + ?line {ReceiverNeg,MrefNeg} = my_spawn_monitor(fun()-> give_away_receiver(T2,Parent) end), ?line give_me = receive_any(), ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,ReceiverNeg,"A deleted table")), ?line T3 = ets_new(foo,[public | Opts]), - spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")), + my_spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")), Parent ! done end), ?line done = receive_any(), @@ -2359,7 +2356,7 @@ setopts_do(Opts) -> Self = self(), ?line T = ets_new(foo,[named_table, private | Opts]), ?line none = ets:info(T,heir), - Heir = spawn_link(fun()->heir_heir(Self) end), + Heir = my_spawn_link(fun()->heir_heir(Self) end), ?line ets:setopts(T,{heir,Heir,"Data"}), ?line Heir = ets:info(T,heir), ?line ets:setopts(T,{heir,self(),"Data"}), @@ -2410,14 +2407,14 @@ bad_table(Config) when is_list(Config) -> bad_table_do(Opts, DummyFile) -> Parent = self(), - {Pid,Mref} = spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]), - Priv = ets_new(priv,[private | Opts]), - ets_new(prot,[protected,named_table | Opts]), - Prot = ets_new(prot,[protected | Opts]), - Parent ! {self(),Priv,Prot}, - die_please = receive_any() - end, - [link, monitor]), + {Pid,Mref} = my_spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]), + Priv = ets_new(priv,[private | Opts]), + ets_new(prot,[protected,named_table | Opts]), + Prot = ets_new(prot,[protected | Opts]), + Parent ! {self(),Priv,Prot}, + die_please = receive_any() + end, + [link, monitor]), {Pid,Priv,Prot} = receive_any(), MatchSpec = {{key,'_'}, [], ['$$']}, Fun = fun(X,_) -> X end, @@ -3263,7 +3260,7 @@ delete_large_named_table_1(Name, Flags, Data, Fix) -> ?line lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data) end, Parent = self(), - Pid = spawn_link(fun() -> + Pid = my_spawn_link(fun() -> receive {trace,Parent,call,_} -> ets_new(Name, [named_table]) @@ -3625,7 +3622,7 @@ cycle(Tab, L) -> ets:insert(Tab,list_to_tuple(L)), cycle(Tab, tl(L)++[hd(L)]). -dynamic_go() -> spawn_link(fun dynamic_init/0). +dynamic_go() -> my_spawn_link(fun dynamic_init/0). dynamic_init() -> [dyn_lookup(?MODULE) || _ <- lists:seq(1, 10)]. @@ -3852,7 +3849,7 @@ safe_fixtable_do(Opts) -> Self = self(), ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed), %% Test that an unjustified 'unfix' is a no-op. - {Pid,MRef} = spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end), + {Pid,MRef} = my_spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end), {'DOWN', MRef, process, Pid, normal} = receive M -> M end, ?line true = ets:info(Tab,fixed), ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed), @@ -4256,7 +4253,7 @@ do_heavy_concurrent(Opts) -> ?line ok = fill_tab2(Tab, 0, Size), ?line Procs = lists:map( fun (N) -> - spawn_link( + my_spawn_link( fun () -> do_heavy_concurrent_proc(Tab, Size, N) end) @@ -4860,12 +4857,7 @@ otp_7665_act(Tab,Min,Max,DelNr) -> %% Whitebox testing of meta name table hashing. meta_wb(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - ?line erts_debug:set_internal_state(available_internal_state, true), - try - repeat_for_opts(meta_wb_do) - after - erts_debug:set_internal_state(available_internal_state, false) - end, + repeat_for_opts(meta_wb_do), ?line verify_etsmem(EtsMem). @@ -4934,12 +4926,15 @@ colliding_names(Name) -> grow_shrink(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - grow_shrink_0(lists:seq(3071, 5000), EtsMem). + ?line grow_shrink_0(lists:seq(3071, 5000), EtsMem), + ?line verify_etsmem(EtsMem). grow_shrink_0([N|Ns], EtsMem) -> ?line grow_shrink_1(N, [set]), ?line grow_shrink_1(N, [ordered_set]), - ?line verify_etsmem(EtsMem), + %% Verifying ets-memory here takes too long time, since + %% lock-free allocators were introduced... + %% ?line verify_etsmem(EtsMem), grow_shrink_0(Ns, EtsMem); grow_shrink_0([], _) -> ok. @@ -4986,13 +4981,13 @@ grow_pseudo_deleted_do(Type) -> ?line Left = ets:info(T,size), ?line Mult = get_kept_objects(T), filltabstr(T,Mult), - spawn_opt(fun()-> ?line true = ets:info(T,fixed), - Self ! start, - io:format("Starting to filltabstr... ~p\n",[now()]), - filltabstr(T,Mult,Mult+10000), - io:format("Done with filltabstr. ~p\n",[now()]), - Self ! done - end, [link, {scheduler,2}]), + my_spawn_opt(fun()-> ?line true = ets:info(T,fixed), + Self ! start, + io:format("Starting to filltabstr... ~p\n",[now()]), + filltabstr(T,Mult,Mult+10000), + io:format("Done with filltabstr. ~p\n",[now()]), + Self ! done + end, [link, {scheduler,2}]), ?line start = receive_any(), io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]), ?line true = ets:safe_fixtable(T,false), @@ -5026,13 +5021,13 @@ shrink_pseudo_deleted_do(Type) -> [true]}]), ?line Half = ets:info(T,size), ?line Half = get_kept_objects(T), - spawn_opt(fun()-> ?line true = ets:info(T,fixed), - Self ! start, - io:format("Starting to delete... ~p\n",[now()]), - del_one_by_one_set(T,1,Half+1), - io:format("Done with delete. ~p\n",[now()]), - Self ! done - end, [link, {scheduler,2}]), + my_spawn_opt(fun()-> ?line true = ets:info(T,fixed), + Self ! start, + io:format("Starting to delete... ~p\n",[now()]), + del_one_by_one_set(T,1,Half+1), + io:format("Done with delete. ~p\n",[now()]), + Self ! done + end, [link, {scheduler,2}]), ?line start = receive_any(), io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]), ?line true = ets:safe_fixtable(T,false), @@ -5189,24 +5184,24 @@ smp_unfix_fix_do() -> ?line Deleted = get_kept_objects(T), {Child, Mref} = - spawn_opt(fun()-> ?line true = ets:info(T,fixed), - Parent ! start, - io:format("Child waiting for table to be unfixed... now=~p mem=~p\n", - [now(),ets:info(T,memory)]), - repeat_while(fun()-> ets:info(T,fixed) end), - io:format("Table unfixed. Child Fixating! now=~p mem=~p\n", - [now(),ets:info(T,memory)]), - ?line true = ets:safe_fixtable(T,true), - repeat_while(fun(Key) when Key =< NumOfObjs -> - ets:delete(T,Key), {true,Key+1}; - (Key) -> {false,Key} - end, - Deleted), - ?line 0 = ets:info(T,size), - ?line true = get_kept_objects(T) >= Left, - ?line done = receive_any() - end, - [link, monitor, {scheduler,2}]), + my_spawn_opt(fun()-> ?line true = ets:info(T,fixed), + Parent ! start, + io:format("Child waiting for table to be unfixed... now=~p mem=~p\n", + [now(),ets:info(T,memory)]), + repeat_while(fun()-> ets:info(T,fixed) end), + io:format("Table unfixed. Child Fixating! now=~p mem=~p\n", + [now(),ets:info(T,memory)]), + ?line true = ets:safe_fixtable(T,true), + repeat_while(fun(Key) when Key =< NumOfObjs -> + ets:delete(T,Key), {true,Key+1}; + (Key) -> {false,Key} + end, + Deleted), + ?line 0 = ets:info(T,size), + ?line true = get_kept_objects(T) >= Left, + ?line done = receive_any() + end, + [link, monitor, {scheduler,2}]), ?line start = receive_any(), ?line true = ets:info(T,fixed), @@ -5237,11 +5232,11 @@ otp_8166_do(WC) -> Deleted = NumOfObjs div 2, filltabint(T,NumOfObjs), {ReaderPid, ReaderMref} = - spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end, - [link, monitor, {scheduler,2}]), + my_spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end, + [link, monitor, {scheduler,2}]), {ZombieCrPid, ZombieCrMref} = - spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end, - [link, monitor, {scheduler,3}]), + my_spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end, + [link, monitor, {scheduler,3}]), repeat(fun() -> ZombieCrPid ! {loop, self()}, zombies_created = receive_any(), @@ -5501,7 +5496,7 @@ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> io:format("smp starting ~p workers\n",[NumOfProcs]), Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], Parent = self(), - Pids = [spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end) + Pids = [my_spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end) || Seed <- Seeds], case Laps of infinite -> Pids; @@ -5550,31 +5545,30 @@ my_tab_to_list(_Ts,'$end_of_table', Acc) -> lists:reverse(Acc); my_tab_to_list(Ts,Key, Acc) -> my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)| Acc]). -wait_for_all_schedulers_online_to_execute() -> - PMs = lists:map(fun (Sched) -> - spawn_opt(fun () -> ok end, - [monitor, {scheduler, Sched}]) - end, - lists:seq(1,erlang:system_info(schedulers_online))), - lists:foreach(fun ({P, M}) -> - receive - {'DOWN', M, process, P, _} -> ok - end - end, - PMs), - ok. + +wait_for_memory_deallocations() -> + try + erts_debug:set_internal_state(wait, deallocations) + catch + error:undef -> + erts_debug:set_internal_state(available_internal_state, true), + wait_for_memory_deallocations() + end. + etsmem() -> - %% Wait until it is guaranteed that all already scheduled - %% deallocations of DbTable structures have completed. - wait_for_all_schedulers_online_to_execute(), + wait_for_memory_deallocations(), AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size), ets:info(T,memory),ets:info(T,type)} end, ets:all()), + + EtsAllocInfo = erlang:system_info({allocator,ets_alloc}), + ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end, + Mem = - {try erlang:memory(ets) catch error:notsup -> notsup end, - case erlang:system_info({allocator,ets_alloc}) of + {ErlangMemoryEts, + case EtsAllocInfo of false -> undefined; MemInfo -> CS = lists:foldl( @@ -5651,6 +5645,7 @@ spawn_logger(Procs) -> true -> exit(Proc, kill); _ -> ok end, + erlang:display(process_info(Proc)), receive {'DOWN', Mon, _, _, _} -> ok @@ -5686,7 +5681,7 @@ wait_for_test_procs(Kill) -> ets_test_spawn_logger ! {sync_test_procs, Kill, self()}, receive test_procs_synced -> ok end. -log_test_proc(Proc) -> +log_test_proc(Proc) when is_pid(Proc) -> ets_test_spawn_logger ! {new_test_proc, Proc}, Proc. @@ -5698,9 +5693,17 @@ my_spawn_link(Fun) -> log_test_proc(spawn_link(Fun)). my_spawn_link(M,F,A) -> log_test_proc(spawn_link(M,F,A)). %%my_spawn_link(N,M,F,A) -> log_test_proc(spawn_link(N,M,F,A)). -my_spawn_opt(Fun,Opts) -> log_test_proc(spawn_opt(Fun,Opts)). -%%my_spawn_opt(M,F,A,Opts) -> log_test_proc(spawn_opt(M,F,A,Opts)). -%%my_spawn_opt(N,M,F,A,Opts) -> log_test_proc(spawn_opt(N,M,F,A,Opts)). +my_spawn_opt(Fun,Opts) -> + case spawn_opt(Fun,Opts) of + Pid when is_pid(Pid) -> log_test_proc(Pid); + {Pid, _} = Res when is_pid(Pid) -> log_test_proc(Pid), Res + end. + +my_spawn_monitor(Fun) -> + Res = spawn_monitor(Fun), + {Pid, _} = Res, + log_test_proc(Pid), + Res. repeat(_Fun, 0) -> ok; @@ -5763,11 +5766,11 @@ spawn_monitor_with_pid(Pid, Fun, N, M) when N > M*10 -> spawn_monitor_with_pid(Pid, Fun, N, M*10); spawn_monitor_with_pid(Pid, Fun, N, M) -> ?line false = is_process_alive(Pid), - case spawn(fun()-> case self() of - Pid -> Fun(); - _ -> die - end - end) of + case my_spawn(fun()-> case self() of + Pid -> Fun(); + _ -> die + end + end) of Pid -> {Pid, erlang:monitor(process, Pid)}; Other -> diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index a614d6595d..7fb8d54f2d 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -694,7 +694,7 @@ multicall_down(Config) when is_list(Config) -> %% We use 'global' as a gen_server to call. ?line {Good, Bad} = gen_server:multi_call([Name, node()], global_name_server, - {whereis, gurkburk}, + info, 3000), io:format("good = ~p, bad = ~p~n", [Good, Bad]), ?line [Name] = Bad, diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 98eeaee118..9be547c690 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -6118,6 +6118,7 @@ otp_6964(Config) when is_list(Config) -> qlc:e(Q, [{max_list_size,64*1024},{tmpdir_usage,Use}]) end, D = erlang:system_flag(backtrace_depth, 0), + try 20000 = length(F(allowed)), ErrReply = F(not_allowed), {error, qlc, {tmpdir_usage,joining}} = ErrReply, @@ -6129,8 +6130,10 @@ otp_6964(Config) when is_list(Config) -> 20000 = length(F(info_msg)), {info, joining} = qlc_SUITE:read_error_logger(), 20000 = length(F(error_msg)), - {error, joining} = qlc_SUITE:read_error_logger(), - _ = erlang:system_flag(backtrace_depth, D), + {error, joining} = qlc_SUITE:read_error_logger() + after + _ = erlang:system_flag(backtrace_depth, D) + end, qlc_SUITE:uninstall_error_logger()">>], ?line run(Config, T1), @@ -6632,7 +6635,7 @@ otp_7232(Config) when is_list(Config) -> {call,_, {remote,_,{atom,_,qlc},{atom,_,sort}}, [{cons,_, - {'fun',_,{function,math,sqrt,_}}, + {'fun',_,{function,{atom,_,math},{atom,_,sqrt},_}}, {cons,_, {string,_,\"<0.4.1>\"}, % could use list_to_pid.. {cons,_,{string,_,\"#Ref<\"++_},{nil,_}}}}, diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl index 0cca030b3d..8a2cb5ea6b 100644 --- a/lib/stdlib/test/stdlib_SUITE.erl +++ b/lib/stdlib/test/stdlib_SUITE.erl @@ -33,8 +33,7 @@ -export([init_per_testcase/2, end_per_testcase/2]). % Test cases must be exported. --export([app_test/1]). --define(cases, [app_test]). +-export([app_test/1, appup_test/1]). %% %% all/1 @@ -42,7 +41,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app_test]. + [app_test, appup_test]. groups() -> []. @@ -79,3 +78,61 @@ app_test(Config) when is_list(Config) -> ?t:app_test(stdlib), ok. +%% Test that appup allows upgrade from/downgrade to a maximum of two +%% major releases back. +appup_test(_Config) -> + application:load(stdlib), + {_,_,Vsn} = lists:keyfind(stdlib,1,application:loaded_applications()), + AppupFile = filename:join([code:lib_dir(stdlib),ebin,"stdlib.appup"]), + {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile), + ct:log("~p~n",[AppupScript]), + {OkVsns,NokVsns} = create_test_vsns(Vsn), + check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), + check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + check_appup(NokVsns,UpFrom,error), + check_appup(NokVsns,DownTo,error), + ok. + +create_test_vsns(Current) -> + [XStr,YStr|Rest] = string:tokens(Current,"."), + X = list_to_integer(XStr), + Y = list_to_integer(YStr), + SecondMajor = vsn(X,Y-2), + SecondMinor = SecondMajor ++ ".1.3", + FirstMajor = vsn(X,Y-1), + FirstMinor = FirstMajor ++ ".57", + ThisMajor = vsn(X,Y), + This = + case Rest of + [] -> + []; + ["1"] -> + [ThisMajor]; + _ -> + ThisMinor = ThisMajor ++ ".1", + [ThisMajor,ThisMinor] + end, + OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], + + ThirdMajor = vsn(X,Y-3), + ThirdMinor = ThirdMajor ++ ".10.12", + Illegal = ThisMajor ++ ",1", + Newer1Major = vsn(X,Y+1), + Newer1Minor = Newer1Major ++ ".1", + Newer2Major = ThisMajor ++ "1", + NokVsns = [ThirdMajor,ThirdMinor, + Illegal, + Newer1Major,Newer1Minor, + Newer2Major], + {OkVsns,NokVsns}. + +vsn(X,Y) -> + integer_to_list(X) ++ "." ++ integer_to_list(Y). + +check_appup([Vsn|Vsns],Instrs,Expected) -> + case systools_relup:appup_search_for_version(Vsn, Instrs) of + Expected -> check_appup(Vsns,Instrs,Expected); + Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other}) + end; +check_appup([],_,_) -> + ok. diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index e709cf62ba..d3d140abbc 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -29,7 +29,8 @@ end_per_testcase/2]). %% Internal export --export([init/1, terminate_all_children/1]). +-export([init/1, terminate_all_children/1, + middle9212/0, gen_server9212/0, handle_info/2]). %% API tests -export([ sup_start_normal/1, sup_start_ignore_init/1, @@ -58,7 +59,8 @@ -export([child_unlink/1, tree/1, count_children_memory/1, do_not_save_start_parameters_for_temporary_children/1, do_not_save_child_specs_for_temporary_children/1, - simple_one_for_one_scale_many_temporary_children/1]). + simple_one_for_one_scale_many_temporary_children/1, + simple_global_supervisor/1]). %%------------------------------------------------------------------------- @@ -77,7 +79,8 @@ all() -> {group, abnormal_termination}, child_unlink, tree, count_children_memory, do_not_save_start_parameters_for_temporary_children, do_not_save_child_specs_for_temporary_children, - simple_one_for_one_scale_many_temporary_children, temporary_bystander]. + simple_one_for_one_scale_many_temporary_children, temporary_bystander, + simple_global_supervisor]. groups() -> [{sup_start, [], @@ -120,7 +123,9 @@ end_per_group(_GroupName, Config) -> init_per_testcase(count_children_memory, Config) -> try erlang:memory() of - _ -> Config + _ -> + erts_debug:set_internal_state(available_internal_state, true), + Config catch error:notsup -> {skip, "+Meamin used during test; erlang:memory/1 not available"} end; @@ -128,6 +133,9 @@ init_per_testcase(_Case, Config) -> erlang:display(_Case), Config. +end_per_testcase(count_children_memory, _Config) -> + catch erts_debug:set_internal_state(available_internal_state, false), + ok; end_per_testcase(_Case, _Config) -> ok. @@ -1136,25 +1144,25 @@ count_children_memory(Config) when is_list(Config) -> [supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)], garbage_collect(), - _Size1 = erlang:memory(processes_used), + _Size1 = proc_memory(), Children = supervisor:which_children(sup_test), - _Size2 = erlang:memory(processes_used), + _Size2 = proc_memory(), ChildCount = get_child_counts(sup_test), - _Size3 = erlang:memory(processes_used), + _Size3 = proc_memory(), [supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)], garbage_collect(), Children2 = supervisor:which_children(sup_test), - Size4 = erlang:memory(processes_used), + Size4 = proc_memory(), ChildCount2 = get_child_counts(sup_test), - Size5 = erlang:memory(processes_used), + Size5 = proc_memory(), garbage_collect(), Children3 = supervisor:which_children(sup_test), - Size6 = erlang:memory(processes_used), + Size6 = proc_memory(), ChildCount3 = get_child_counts(sup_test), - Size7 = erlang:memory(processes_used), + Size7 = proc_memory(), 1000 = length(Children), [1,1000,0,1000] = ChildCount, @@ -1180,6 +1188,10 @@ count_children_memory(Config) when is_list(Config) -> [terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3], [1,0,0,0] = get_child_counts(sup_test). +proc_memory() -> + erts_debug:set_internal_state(wait, deallocations), + erlang:memory(processes_used). + %%------------------------------------------------------------------------- do_not_save_start_parameters_for_temporary_children(doc) -> ["Temporary children shall not be restarted so they should not " @@ -1379,6 +1391,92 @@ terminate_all_children([]) -> done. +%%------------------------------------------------------------------------- +%% OTP-9212. Restart of global supervisor. +simple_global_supervisor(_Config) -> + kill_supervisor(), + kill_worker(), + exit_worker(), + restart_worker(), + ok. + +kill_supervisor() -> + {Top, Sup2_1, Server_1} = start9212(), + + %% Killing a supervisor isn't really supported, but try it anyway... + exit(Sup2_1, kill), + timer:sleep(200), + Sup2_2 = global:whereis_name(sup2), + Server_2 = global:whereis_name(server), + true = is_pid(Sup2_2), + true = is_pid(Server_2), + true = Sup2_1 =/= Sup2_2, + true = Server_1 =/= Server_2, + + stop9212(Top). + +handle_info({fail, With, After}, _State) -> + timer:sleep(After), + erlang:error(With). + +kill_worker() -> + {Top, _Sup2, Server_1} = start9212(), + exit(Server_1, kill), + timer:sleep(200), + Server_2 = global:whereis_name(server), + true = is_pid(Server_2), + true = Server_1 =/= Server_2, + stop9212(Top). + +exit_worker() -> + %% Very much the same as kill_worker(). + {Top, _Sup2, Server_1} = start9212(), + Server_1 ! {fail, normal, 0}, + timer:sleep(200), + Server_2 = global:whereis_name(server), + true = is_pid(Server_2), + true = Server_1 =/= Server_2, + stop9212(Top). + +restart_worker() -> + {Top, _Sup2, Server_1} = start9212(), + ok = supervisor:terminate_child({global, sup2}, child), + {ok, _Child} = supervisor:restart_child({global, sup2}, child), + Server_2 = global:whereis_name(server), + true = is_pid(Server_2), + true = Server_1 =/= Server_2, + stop9212(Top). + +start9212() -> + Middle = {middle,{?MODULE,middle9212,[]}, permanent,2000,supervisor,[]}, + InitResult = {ok, {{one_for_all,3,60}, [Middle]}}, + {ok, TopPid} = start_link(InitResult), + + Sup2 = global:whereis_name(sup2), + Server = global:whereis_name(server), + true = is_pid(Sup2), + true = is_pid(Server), + {TopPid, Sup2, Server}. + +stop9212(Top) -> + Old = process_flag(trap_exit, true), + exit(Top, kill), + timer:sleep(200), + undefined = global:whereis_name(sup2), + undefined = global:whereis_name(server), + check_exit([Top]), + _ = process_flag(trap_exit, Old), + ok. + +middle9212() -> + Child = {child, {?MODULE,gen_server9212,[]},permanent, 2000, worker, []}, + InitResult = {ok, {{one_for_all,3,60}, [Child]}}, + supervisor:start_link({global,sup2}, ?MODULE, InitResult). + +gen_server9212() -> + InitResult = {ok, []}, + gen_server:start_link({global,server}, ?MODULE, InitResult, []). + %%------------------------------------------------------------------------- terminate(Pid, Reason) when Reason =/= supervisor -> diff --git a/lib/stdlib/test/supervisor_bridge_SUITE.erl b/lib/stdlib/test/supervisor_bridge_SUITE.erl index c4d696564d..b3056ff41a 100644 --- a/lib/stdlib/test/supervisor_bridge_SUITE.erl +++ b/lib/stdlib/test/supervisor_bridge_SUITE.erl @@ -19,8 +19,9 @@ -module(supervisor_bridge_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,starting/1, - mini_terminate/1,mini_die/1,badstart/1]). --export([client/1,init/1,internal_loop_init/1,terminate/2]). + mini_terminate/1,mini_die/1,badstart/1, + simple_global_supervisor/1]). +-export([client/1,init/1,internal_loop_init/1,terminate/2,server9212/0]). -include_lib("test_server/include/test_server.hrl"). -define(bridge_name,supervisor_bridge_SUITE_server). @@ -31,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [starting, mini_terminate, mini_die, badstart]. + [starting, mini_terminate, mini_die, badstart, simple_global_supervisor]. groups() -> []. @@ -138,7 +139,9 @@ init(3) -> receive {InternalPid,init_done} -> {ok,InternalPid,self()} - end. + end; +init({4,Result}) -> + Result. internal_loop_init(Parent) -> register(?work_bridge_name, self()), @@ -160,7 +163,9 @@ terminate(Reason,{Parent,Worker}) -> io:format("Terminating bridge...\n"), exit(Worker,kill), Parent ! {dying,Reason}, - anything. + anything; +terminate(_Reason, _State) -> + any. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -197,3 +202,30 @@ badstart(Config) when is_list(Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% OTP-9212. Restart of global supervisor. + +simple_global_supervisor(suite) -> []; +simple_global_supervisor(doc) -> "Globally registered supervisor."; +simple_global_supervisor(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap({seconds,10}), + + Child = {child, {?MODULE,server9212,[]}, permanent, 2000, worker, []}, + InitResult = {ok, {{one_for_all,3,60}, [Child]}}, + {ok, Sup} = + supervisor:start_link({local,bridge9212}, ?MODULE, {4,InitResult}), + + BN_1 = global:whereis_name(?bridge_name), + ?line exit(BN_1, kill), + timer:sleep(200), + BN_2 = global:whereis_name(?bridge_name), + ?line true = is_pid(BN_2), + ?line true = BN_1 =/= BN_2, + + ?line process_flag(trap_exit, true), + exit(Sup, kill), + ?line receive {'EXIT', Sup, killed} -> ok end, + ?line test_server:timetrap_cancel(Dog), + ok. + +server9212() -> + supervisor_bridge:start_link({global,?bridge_name}, ?MODULE, 3). diff --git a/lib/syntax_tools/doc/Makefile b/lib/syntax_tools/doc/Makefile index 6afd16f669..d9981de880 100644 --- a/lib/syntax_tools/doc/Makefile +++ b/lib/syntax_tools/doc/Makefile @@ -78,12 +78,3 @@ release_docs_spec: docs release_spec: - - - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- -#-include make.dep - - diff --git a/lib/syntax_tools/doc/src/make.dep b/lib/syntax_tools/doc/src/make.dep deleted file mode 100644 index acc76857bb..0000000000 --- a/lib/syntax_tools/doc/src/make.dep +++ /dev/null @@ -1,22 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex chapter.tex epp_dodger.tex erl_comment_scan.tex \ - erl_prettypr.tex erl_recomment.tex erl_syntax.tex \ - erl_syntax_lib.tex erl_tidy.tex igor.tex part.tex \ - prettypr.tex ref_man.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 9df5f26454..7f58fda519 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -6093,11 +6093,16 @@ implicit_fun_name(Node) -> {'fun', Pos, {function, Atom, Arity}} -> arity_qualifier(set_pos(atom(Atom), Pos), set_pos(integer(Arity), Pos)); - {'fun', Pos, {function, Module, Atom, Arity}} -> + {'fun', Pos, {function, Module, Atom, Arity}} + when is_atom(Module), is_atom(Atom), is_integer(Arity) -> + %% Backward compatibility with pre-R15 abstract format. module_qualifier(set_pos(atom(Module), Pos), arity_qualifier( set_pos(atom(Atom), Pos), set_pos(integer(Arity), Pos))); + {'fun', Pos, {function, Module, Atom, Arity}} -> + %% New in R15: fun M:F/A. + module_qualifier(Module, arity_qualifier(Atom, Arity)); Node1 -> data(Node1) end. diff --git a/lib/test_server/doc/src/Makefile b/lib/test_server/doc/src/Makefile index c7ba415e5b..f0be284324 100644 --- a/lib/test_server/doc/src/Makefile +++ b/lib/test_server/doc/src/Makefile @@ -133,9 +133,3 @@ release_docs_spec: docs release_spec: release_tests_spec: - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -include make.dep diff --git a/lib/test_server/doc/src/make.dep b/lib/test_server/doc/src/make.dep deleted file mode 100644 index ee9100bd08..0000000000 --- a/lib/test_server/doc/src/make.dep +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: basics_chapter.tex book.tex example_chapter.tex \ - part.tex ref_man.tex run_test_chapter.tex \ - test_server_app.tex test_server_ctrl.tex \ - test_server.tex test_spec_chapter.tex \ - write_framework_chapter.tex \ - write_test_chapter.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl index c94d4627f9..e2fd951d9e 100644 --- a/lib/test_server/src/erl2html2.erl +++ b/lib/test_server/src/erl2html2.erl @@ -32,32 +32,34 @@ %-------------------------------------------------------------------- -module(erl2html2). --export([convert/2]). +-export([convert/2, convert/3]). convert([], _Dest) -> % Fake clause. ok; convert(File, Dest) -> + %% The generated code uses the BGCOLOR attribute in the + %% BODY tag, which wasn't valid until HTML 3.2. Also, + %% good HTML should either override all colour attributes + %% or none of them -- *never* just a few. + %% + %% FIXME: The colours should *really* be set with + %% stylesheets... + Header = ["<!DOCTYPE HTML PUBLIC " + "\"-//W3C//DTD HTML 3.2 Final//EN\">\n" + "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" + "<html>\n" + "<head><title>", File, "</title></head>\n\n" + "<body bgcolor=\"white\" text=\"black\"" + " link=\"blue\" vlink=\"purple\" alink=\"red\">\n"], + convert(File, Dest, Header). + +convert(File, Dest, Header) -> case file:read_file(File) of {ok, Bin} -> Code=binary_to_list(Bin), statistics(runtime), - %% The generated code uses the BGCOLOR attribute in the - %% BODY tag, which wasn't valid until HTML 3.2. Also, - %% good HTML should either override all colour attributes - %% or none of them -- *never* just a few. - %% - %% FIXME: The colours should *really* be set with - %% stylesheets... - Html0 - = ["<!DOCTYPE HTML PUBLIC " - "\"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<html>\n" - "<head><title>", File, "</title></head>\n\n" - "<body bgcolor=\"white\" text=\"black\"" - " link=\"blue\" vlink=\"purple\" alink=\"red\">\n"], {Html1, Lines} = root(Code, [], 1), - Html = [Html0, + Html = [Header, "<pre>\n", Html1, "</pre>\n", footer(Lines),"</body>\n</html>\n"], file:write_file(Dest, Html); @@ -173,10 +175,11 @@ linenum(Line) -> end, [A,Pred,integer_to_list(Line),":"]. -footer(Lines) -> - {_, Time} = statistics(runtime), -% io:format("Converted ~p lines in ~.2f Seconds.~n", -% [Lines, Time/1000]), - S = "<i>The transformation of this file (~p lines) took ~.2f seconds</i>", - F = lists:flatten(io_lib:format(S, [Lines, Time/1000])), - ["<hr size=1>",F,"<br>\n"]. +footer(_Lines) -> + "". +%% {_, Time} = statistics(runtime), +%% io:format("Converted ~p lines in ~.2f Seconds.~n", +%% [Lines, Time/1000]), +%% S = "<i>The transformation of this file (~p lines) took ~.2f seconds</i>", +%% F = lists:flatten(io_lib:format(S, [Lines, Time/1000])), +%% ["<hr size=1>",F,"<br>\n"]. diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 49f97686a0..743e6c1d29 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -611,6 +611,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> print(minor, "Test case started with:\n~s:~s(~p)\n", [Mod,Func,Args2Print]), print(minor, "Current directory is ~p\n", [Cwd]), print_timestamp(minor,"Started at "), + print(minor, "", []), TCCallback = get(test_server_testcase_callback), LogOpts = get(test_server_logopts), Ref = make_ref(), @@ -1525,7 +1526,7 @@ get_loc(Pid) -> get_mf(MFs) -> get_mf(MFs, {undefined,undefined}). -get_mf([MF|MFs], Found) when is_tuple(MF) -> +get_mf([MF|MFs], _Found) when is_tuple(MF) -> ModFunc = {Mod,_} = case MF of {M,F,_} -> {M,F}; MF -> MF diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 4fad86d16d..9fd0adbfc8 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -214,6 +214,9 @@ X == auto_skip -> skipped; true -> X end). +-define(auto_skip_color, "#FFA64D"). +-define(user_skip_color, "#FF8000"). + -record(state,{jobs=[],levels={1,19,10}, multiply_timetraps=1,scale_timetraps=true, finish=false, @@ -1668,7 +1671,7 @@ do_test_cases(TopCases, SkipCases, do_test_cases(TopCases, SkipCases, Config, TimetrapData) when is_list(TopCases), is_tuple(TimetrapData) -> - start_log_file(), + {ok,TestDir} = start_log_file(), FwMod = case os:getenv("TEST_SERVER_FRAMEWORK") of FW when FW =:= false; FW =:= "undefined" -> ?MODULE; @@ -1692,60 +1695,86 @@ do_test_cases(TopCases, SkipCases, [print_if_known(N, {", ~w test cases",[N]}, {" (with repeated test cases)",[]})]), Test = get(test_server_name), - test_server_sup:framework_call(report, [tests_start,{Test,N}]), + TestName = if is_list(Test) -> + lists:flatten(io_lib:format("~s", [Test])); + true -> + lists:flatten(io_lib:format("~p", [Test])) + end, + TestDescr = "Test " ++ TestName ++ " results", - Header = - case test_server_sup:framework_call(overview_html_header, [Test], "") of - "" -> - TestName = lists:flatten(io_lib:format("~p", [Test])), - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", - "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n", - "<html>\n", - "<head><title>Test ", TestName, " results</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", - "</head>\n", - "<body bgcolor=\"white\" text=\"black\" ", - "link=\"blue\" vlink=\"purple\" alink=\"red\">", - "<h2>Results from test ", TestName, "</h2>\n"]; - Html -> - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", - "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n" | Html] + test_server_sup:framework_call(report, [tests_start,{Test,N}]), + {Header,Footer} = + case test_server_sup:framework_call(get_html_wrapper, + [TestDescr,true,TestDir], "") of + Empty when (Empty == "") ; (element(2,Empty) == "") -> + put(basic_html, true), + {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", + "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n", + "<html>\n", + "<head><title>", TestDescr, "</title>\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "</head>\n", + "<body bgcolor=\"white\" text=\"black\" ", + "link=\"blue\" vlink=\"purple\" alink=\"red\">", + "<h2>Results for test ", TestName, "</h2>\n"], + "\n</body>\n</html>\n"}; + {basic_html,Html0,Html1} -> + put(basic_html, true), + {Html0++["<h1>Results for <i>",TestName,"</i></h1>\n"], + Html1}; + {xhtml,Html0,Html1} -> + put(basic_html, false), + {Html0++["<h1>Results for <i>",TestName,"</i></h1>\n"], + Html1} end, - print(html, Header, []), - print_timestamp(html, "Test started at "), - print(html, "<p>Host:<br>\n"), + print(html, Header), + + print(html, xhtml("<p>", "<h4>")), + print_timestamp(html, "Test started at "), + print(html, xhtml("</p>", "</h4>")), + + print(html, xhtml("\n<p><b>Host info:</b><br>\n", + "\n<p><b>Host info:</b><br />\n")), print_who(test_server_sup:hoststr(), test_server_sup:get_username()), - print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n", + print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n", + "<br />Used Erlang v~s in \"~s\"</p>\n"), [erlang:system_info(version), code:root_dir()]), - + if FwMod == ?MODULE -> - print(html, "<p>Target:<br>\n"), + print(html, xhtml("\n<p><b>Target Info:</b><br>\n", + "\n<p><b>Target Info:</b><br />\n")), print_who(TI#target_info.host, TI#target_info.username), - print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n", + print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n", + "<br />Used Erlang v~s in \"~s\"</p>\n"), [TI#target_info.version, TI#target_info.root_dir]); - true -> + true -> case test_server_sup:framework_call(target_info, []) of TargetInfo when is_list(TargetInfo), length(TargetInfo) > 0 -> - print(html, "<p>Target:<br>\n"), - print(html, "~s\n", [TargetInfo]); + print(html, xhtml("\n<p><b>Target info:</b><br>\n", + "\n<p><b>Target info:</b><br />\n")), + print(html, "~s</p>\n", [TargetInfo]); _ -> ok end end, - + print(html, - "<p><a href=\"~s\">Full textual log</a>\n" - "<br><a href=\"~s\">Coverage log</a>\n", + "<p><ul>\n" + "<li><a href=\"~s\">Full textual log</a></li>\n" + "<li><a href=\"~s\">Coverage log</a></li>\n</ul></p>\n", [?suitelog_name,?coverlog_name]), - print(html,"<p>~s" - "<p>\n" - "<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">" - "<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>" - "<th>Time</th><th>Result</th><th>Comment</th></tr>\n", - [print_if_known(N, {"Suite contains ~p test cases.\n",[N]}, + print(html, + "<p>~s</p>\n" ++ + xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">", + "<table>") ++ + "<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>" + "<th>Time</th><th>Result</th><th>Comment</th></tr>\n", + [print_if_known(N, {"<i>Executing <b>~p</b> test cases...</i>\n",[N]}, {"",[]})]), + print(html, xhtml("<br>", "<br />")), + print(major, "=cases ~p", [get(test_server_cases)]), print(major, "=user ~s", [TI#target_info.username]), print(major, "=host ~s", [TI#target_info.host]), @@ -1764,6 +1793,9 @@ do_test_cases(TopCases, SkipCases, print(major, "=otp_release ~s", [TI#target_info.otp_release]), print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), + + put(test_server_html_footer, Footer), + run_test_cases(TestSpec, Config, TimetrapData) end; @@ -1773,7 +1805,7 @@ do_test_cases(TopCase, SkipCases, Config, TimetrapSpec) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start_log_file() -> ok | exit({Error,Reason}) +%% start_log_file() -> {ok,TestDirName} | exit({Error,Reason}) %% Stem = string() %% %% Creates the log directories, the major log file and the html log file. @@ -1824,7 +1856,7 @@ start_log_file() -> LogInfo = [{topdir,Dir},{rundir,lists:flatten(TestDir)}], test_server_sup:framework_call(report, [loginfo,LogInfo]), - ok. + {ok,TestDir}. make_html_link(LinkName, Target, Explanation) -> %% if possible use a relative reference to Target. @@ -1881,16 +1913,32 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) -> {ok,Fd} = file:open(AbsName, [write]), Lev = get(test_server_minor_level)+1000, %% far down in the minor levels put(test_server_minor_fd, Fd), - io:fwrite(Fd, - "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<html>\n" - "<head><title>"++cast_to_list(Mod)++"</title>\n" - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n" - "</head>\n" - "<body bgcolor=\"white\" text=\"black\"" - " link=\"blue\" vlink=\"purple\" alink=\"red\">\n", - []), + + TestDescr = io_lib:format("Test ~p:~p result", [Mod,Func]), + {Header,Footer} = + case test_server_sup:framework_call(get_html_wrapper, + [TestDescr,false, + filename:dirname(AbsName)], "") of + Empty when (Empty == "") ; (element(2,Empty) == "") -> + put(basic_html, true), + {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", + "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n", + "<html>\n", + "<head><title>", TestDescr, "</title>\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "</head>\n", + "<body bgcolor=\"white\" text=\"black\" ", + "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"], + "\n</body>\n</html>\n"}; + {basic_html,Html0,Html1} -> + put(basic_html, true), + {Html0,Html1}; + {xhtml,Html0,Html1} -> + put(basic_html, false), + {Html0,Html1} + end, + put(test_server_minor_footer, Footer), + io:fwrite(Fd, Header, []), SrcListing = downcase(cast_to_list(Mod)) ++ ?src_listing_ext, case {filelib:is_file(filename:join(LogDir, SrcListing)), @@ -1913,7 +1961,8 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) -> stop_minor_log_file() -> Fd = get(test_server_minor_fd), - io:fwrite(Fd, "</pre>\n</body>\n</html>\n", []), + Footer = get(test_server_minor_footer), + io:fwrite(Fd, "</pre>\n" ++ Footer, []), file:close(Fd), put(test_server_minor_fd, undefined). @@ -1992,12 +2041,29 @@ html_convert_modules([]) -> ok. %% Convert source code to HTML if possible and needed. html_possibly_convert(Src, SrcInfo, Dest) -> case file:read_file_info(Dest) of - {error,_Reason} -> % no dest file - erl2html2:convert(Src, Dest); - {ok,DestInfo} when DestInfo#file_info.mtime < SrcInfo#file_info.mtime -> - erl2html2:convert(Src, Dest); - {ok,_DestInfo} -> - ok % dest file up to date + {ok,DestInfo} when DestInfo#file_info.mtime >= SrcInfo#file_info.mtime -> + ok; % dest file up to date + _ -> + OutDir = get(test_server_log_dir_base), + Header = + case test_server_sup:framework_call(get_html_wrapper, + ["Module "++Src,false, + OutDir], "") of + Empty when (Empty == "") ; (element(2,Empty) == "") -> + ["<!DOCTYPE HTML PUBLIC", + "\"-//W3C//DTD HTML 3.2 Final//EN\">\n", + "<!-- autogenerated by 'erl2html2' -->\n", + "<html>\n", + "<head><title>Module ", Src, "</title>\n", + "<meta http-equiv=\"cache-control\" ", + "content=\"no-cache\">\n", + "</head>\n", + "<body bgcolor=\"white\" text=\"black\" ", + "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"]; + {_,Html,_} -> + Html + end, + erl2html2:convert(Src, Dest, Header) end. %% Copy all HTML files in InDir to OutDir. @@ -3153,8 +3219,8 @@ skip_case(Type, Ref, CaseNum, Case, Comment, SendSync, Mode) -> skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) -> {{Col0,Col1},_} = get_font_style((CaseNum > 0), Mode), - ResultCol = if Type == auto -> "#ffcc99"; - Type == user -> "#ff9933" + ResultCol = if Type == auto -> ?auto_skip_color; + Type == user -> ?user_skip_color end, Comment1 = reason_to_string(Comment), @@ -3163,9 +3229,9 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) -> print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), print(major, "=result skipped: ~s", [Comment1]), print(2,"*** Skipping test case #~w ~p ***", [CaseNum,{Mod,Func}]), + TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]), print(html, - "<tr valign=top>" - "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>" + TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>" "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>" "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>" "<td>" ++ Col0 ++ "< >" ++ Col1 ++ "</td>" @@ -3561,17 +3627,18 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, test_server_sup:framework_call(report, [tc_start,{?pl2a(Mod),Func}]), print(major, "=case ~p:~p", [Mod, Func]), MinorName = start_minor_log_file(Mod, Func), - print(minor, "<a name=top></a>", []), + print(minor, "<a name=\"top\"></a>", []), MinorBase = filename:basename(MinorName), print(major, "=logfile ~s", [filename:basename(MinorName)]), print_props((RunInit==skip_init), get_props(Mode)), print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), {{Col0,Col1},Style} = get_font_style((RunInit==run_init), Mode), - print(html, "<tr valign=top><td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>" - "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>" - "<td><a href=\"~s\">~p</a></td>" - "<td><a href=\"~s#top\"><</a> <a href=\"~s#end\">></a></td>", - [num2str(Num),Mod,MinorBase,Func,MinorBase,MinorBase]), + TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]), + print(html, TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>" + "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>" + "<td><a href=\"~s\">~p</a></td>" + "<td><a href=\"~s#top\"><</a> <a href=\"~s#end\">></a></td>", + [num2str(Num),Mod,MinorBase,Func,MinorBase,MinorBase]), do_if_parallel(Main, ok, fun erlang:yield/0), %% run the test case @@ -3584,7 +3651,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, {died,DReason,DLoc,DCmt} -> {died,DReason,DLoc,[],DCmt} end, - print(minor, "<a name=end></a>", []), + print(minor, "<a name=\"end\"></a>", []), print_timestamp(minor, "Ended at "), print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]), @@ -3838,9 +3905,10 @@ check_new_crash_dumps(Where) -> progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, Comment, {St0,St1}) -> - {Reason1,{Color,Ret}} = if_auto_skip(Reason, - fun() -> {"#ffcc99",auto_skip} end, - fun() -> {"#ff9933",skip} end), + {Reason1,{Color,Ret}} = + if_auto_skip(Reason, + fun() -> {?auto_skip_color,auto_skip} end, + fun() -> {?user_skip_color,skip} end), print(major, "=result skipped", []), print(1, "*** SKIPPED *** ~s", [get_info_str(Func, CaseNum, get(test_server_cases))]), @@ -3857,7 +3925,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, end, Comment1 = case Comment of "" -> ""; - _ -> "<br>(" ++ to_string(Comment) ++ ")" + _ -> xhtml("<br>(","<br />(") ++ to_string(Comment) ++ ")" end, print(html, "<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>" @@ -3882,8 +3950,8 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T, Comment = case Comment0 of "" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>"; - _ -> "<font color=\"red\">" ++ ErrorReason ++ "</font><br>" ++ - to_string(Comment0) + _ -> "<font color=\"red\">" ++ ErrorReason ++ + xhtml("</font><br>","</font><br />") ++ to_string(Comment0) end, print(html, "<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>" @@ -3908,8 +3976,8 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T, Comment = case Comment0 of "" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>"; - _ -> "<font color=\"red\">" ++ ErrorReason ++ "</font><br>" ++ - to_string(Comment0) + _ -> "<font color=\"red\">" ++ ErrorReason ++ + xhtml("</font><br>","</font><br />") ++ to_string(Comment0) end, print(html, "<td>" ++ St0 ++ "died" ++ St1 ++ "</td>" @@ -3943,7 +4011,8 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, Comment = case Comment0 of "" -> "<font color=\"red\">" ++ ErrorReason2 ++ "</font>"; - _ -> "<font color=\"red\">" ++ ErrorReason2 ++ "</font><br>" ++ + _ -> "<font color=\"red\">" ++ ErrorReason2 ++ + xhtml("</font><br>","</font><br />") ++ to_string(Comment0) end, print(html, @@ -3953,7 +4022,7 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, [TimeStr,Comment]), print(minor, "=== location ~s", [unknown]), {FStr,FormattedReason} = format_exception(Reason), - print(minor, "=== reason = "++FStr, [FormattedReason]), + print(minor, "=== reason = " ++ FStr, [FormattedReason]), failed; progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, @@ -3969,7 +4038,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, Comment = case Comment0 of "" -> ""; - _ -> "<br>" ++ to_string(Comment0) + _ -> xhtml("<br>","<br />") ++ to_string(Comment0) end, FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)), print(html, @@ -3980,7 +4049,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, FormatLoc = test_server_sup:format_loc(Loc), print(minor, "=== location ~s", [FormatLoc]), {FStr,FormattedReason} = format_exception(Reason), - print(minor, "=== reason = "++FStr, [FormattedReason]), + print(minor, "=== reason = " ++ FStr, [FormattedReason]), failed; progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time, @@ -3999,7 +4068,7 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time, _ -> print(major, "=result ok", []), case Comment0 of - "" -> ""; + "" -> "<td></td>"; _ -> "<td>" ++ to_string(Comment0) ++ "</td>" end end, @@ -4349,7 +4418,13 @@ output({html,Msg}, _Sender) -> %% We are writing to a seekable file. Finalise so %% we get complete valid (and viewable) HTML code. %% Then rewind to overwrite the finalising code. - io:put_chars(Fd, "\n</table>\n</body>\n</html>\n"), + io:put_chars(Fd, "\n</table>\n"), + case get(test_server_html_footer) of + undefined -> + io:put_chars(Fd, "</body>\n</html>\n"); + Footer -> + io:put_chars(Fd, Footer) + end, file:position(Fd, Pos); {error, epipe} -> %% The file is not seekable. We cannot erase what @@ -4394,6 +4469,28 @@ output_to_fd(Fd, Msg, _Sender) -> end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% xhtml(BasicHtml, XHtml) -> BasicHtml | XHtml +%% +xhtml(HTML, XHTML) -> + case get(basic_html) of + true -> HTML; + _ -> XHTML + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% odd_or_even() -> "odd" | "even" +%% +odd_or_even() -> + case get(odd_or_even) of + even -> + put(odd_or_even, odd), + "even"; + _ -> + put(odd_or_even, even), + "odd" + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% timestamp_filename_get(Leader) -> string() %% Leader = string() %% @@ -5499,9 +5596,10 @@ write_default_cross_coverlog(TestDir) -> file:open(filename:join(TestDir,?cross_coverlog_name), [write]), write_coverlog_header(CrossCoverLog), io:fwrite(CrossCoverLog, - "No cross cover modules exist for this application,<br>" - "or cross cover analysis is not completed.\n" - "</body></html>\n", []), + ["No cross cover modules exist for this application,", + xhtml("<br>","<br />"), + "or cross cover analysis is not completed.\n" + "</body></html>\n"], []), file:close(CrossCoverLog). write_cover_result_table(CoverLog,Coverage) -> diff --git a/lib/toolbar/doc/src/make.dep b/lib/toolbar/doc/src/make.dep deleted file mode 100644 index d93ff2a315..0000000000 --- a/lib/toolbar/doc/src/make.dep +++ /dev/null @@ -1,26 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex toolbar.tex \ - toolbar_chapter.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: bar.ps create_tool.ps - diff --git a/lib/tools/doc/src/make.dep b/lib/tools/doc/src/make.dep deleted file mode 100644 index 11fa090d6f..0000000000 --- a/lib/tools/doc/src/make.dep +++ /dev/null @@ -1,33 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex cover.tex cover_chapter.tex cprof.tex \ - cprof_chapter.tex eprof.tex erlang_mode.tex \ - erlang_mode_chapter.tex fprof.tex fprof_chapter.tex \ - instrument.tex make.tex part.tex ref_man.tex \ - tags.tex xref.tex xref_chapter.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -cprof.tex: ../../../../system/doc/definitions/term.defs - -xref.tex: ../../../../system/doc/definitions/term.defs - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: venn1.ps venn2.ps - diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index fb9744d759..e21bd1b88c 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -522,7 +522,7 @@ call(Request) -> {?SERVER,Reply} -> Reply end, - erlang:demonitor(Ref), + erlang:demonitor(Ref, [flush]), Return end. @@ -545,7 +545,7 @@ remote_call(Node,Request) -> {?SERVER,Reply} -> Reply end, - erlang:demonitor(Ref), + erlang:demonitor(Ref, [flush]), Return end. diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl index d22f0df164..92f0c45c7b 100644 --- a/lib/tools/src/xref_reader.erl +++ b/lib/tools/src/xref_reader.erl @@ -158,15 +158,20 @@ expr({'try',_Line,Es,Scs,Ccs,As}, S) -> S2 = clauses(Scs, S1), S3 = clauses(Ccs, S2), expr(As, S3); -expr({call, Line, - {remote, _, {atom,_,erlang}, {atom,_,make_fun}}, - [{atom,_,Mod}, {atom,_,Fun}, {integer,_,Arity}]}, S) -> - %% Added in R10B-6. M:F/A. - expr({'fun', Line, {function, Mod, Fun, Arity}}, S); -expr({'fun', Line, {function, Mod, Name, Arity}}, S) -> - %% Added in R10B-6. M:F/A. +expr({'fun', Line, {function, {atom,_,Mod}, + {atom,_,Name}, + {integer,_,Arity}}}, S) -> + %% New format in R15. M:F/A (literals). As = lists:duplicate(Arity, {atom, Line, foo}), external_call(Mod, Name, As, Line, false, S); +expr({'fun', Line, {function, Mod, Name, {integer,_,Arity}}}, S) -> + %% New format in R15. M:F/A (one or more variables). + As = lists:duplicate(Arity, {atom, Line, foo}), + external_call(erlang, apply, [Mod, Name, list2term(As)], Line, true, S); +expr({'fun', Line, {function, Mod, Name, _Arity}}, S) -> + %% New format in R15. M:F/A (one or more variables). + As = {var, Line, '_'}, + external_call(erlang, apply, [Mod, Name, As], Line, true, S); expr({'fun', Line, {function, Name, Arity}, _Extra}, S) -> %% Added in R8. handle_call(local, S#xrefr.module, Name, Arity, Line, S); @@ -286,10 +291,10 @@ check_funarg(W, ArgsList, Line, S) -> expr(ArgsList, S1). funarg({'fun', _, _Clauses, _Extra}, _S) -> true; -funarg({var, _, Var}, S) -> member(Var, S#xrefr.funvars); -funarg({call,_,{remote,_,{atom,_,erlang},{atom,_,make_fun}},_MFA}, _S) -> - %% R10B-6. M:F/A. +funarg({'fun', _, {function,_,_,_}}, _S) -> + %% New abstract format for fun M:F/A in R15. true; +funarg({var, _, Var}, S) -> member(Var, S#xrefr.funvars); funarg(_, _S) -> false. fun_args(apply2, [FunArg, Args]) -> {FunArg, Args}; diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index fe7f92de78..881a3c2997 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -583,21 +583,14 @@ otp_6115_1(Config) -> %% called -- running cover compiled code when there is no cover %% server and thus no ets tables to bump counters in, makes no %% sense. - ?line Pid1 = f1:start_fail(), - - %% If f1 is cover compiled, a process P is started with a - %% reference to the fun created in start_ok/0, and - %% cover:stop() is called, then P should survive. - %% This is because (the fun held by) P always references the current - %% version of the module, and is thus not affected by the cover - %% compiled version being unloaded. - ?line Pid2 = f1:start_ok(), + Pid1 = f1:start_a(), + Pid2 = f1:start_b(), %% Now stop cover ?line cover:stop(), - %% Ensure that f1 is loaded (and not cover compiled), that Pid1 - %% is dead and Pid2 is alive, but with no reference to old code + %% Ensure that f1 is loaded (and not cover compiled), and that + %% both Pid1 and Pid2 are dead. case code:which(f1) of Beam when is_list(Beam) -> ok; @@ -608,19 +601,15 @@ otp_6115_1(Config) -> undefined -> ok; _PI1 -> - RefToOldP = erlang:check_process_code(Pid1, f1), - ?line ?t:fail({"Pid1 still alive", RefToOldP}) + RefToOldP1 = erlang:check_process_code(Pid1, f1), + ?t:fail({"Pid1 still alive", RefToOldP1}) end, case process_info(Pid2) of - PI2 when is_list(PI2) -> - case erlang:check_process_code(Pid2, f2) of - false -> - ok; - true -> - ?line ?t:fail("Pid2 has ref to old code") - end; undefined -> - ?line ?t:fail("Pid2 has died") + ok; + _PI2 -> + RefToOldP2 = erlang:check_process_code(Pid1, f2), + ?t:fail({"Pid2 still alive", RefToOldP2}) end, ?line file:set_cwd(CWD), diff --git a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl index b659e5d818..5399b33f19 100644 --- a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl +++ b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl @@ -1,12 +1,13 @@ -module(f1). --export([start_fail/0, start_ok/0]). +-export([start_a/0, start_b/0]). -start_fail() -> +start_a() -> f2:start(fun() -> - io:format("this does not work\n",[]) + ok end). -start_ok() -> +start_b() -> f2:start(fun fun1/0). + fun1() -> - io:format("this works\n",[]). + ok. diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl index 2f83ab4995..e0876381ca 100644 --- a/lib/tools/test/xref_SUITE.erl +++ b/lib/tools/test/xref_SUITE.erl @@ -46,7 +46,8 @@ -export([ add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, replace/1, update/1, deprecated/1, trycatch/1, - abstract_modules/1, fun_mfa/1, qlc/1]). + abstract_modules/1, fun_mfa/1, fun_mfa_r14/1, + fun_mfa_vars/1, qlc/1]). -export([ analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]). @@ -82,7 +83,7 @@ groups() -> {files, [], [add, default, info, lib, read, read2, remove, replace, update, deprecated, trycatch, abstract_modules, fun_mfa, - qlc]}, + fun_mfa_r14, fun_mfa_vars, qlc]}, {analyses, [], [analyze, basic, md, q, variables, unused_locals]}, {misc, [], [format_error, otp_7423, otp_7831]}]. @@ -1771,6 +1772,88 @@ fun_mfa(Conf) when is_list(Conf) -> ?line ok = file:delete(Beam), ok. +%% Same as the previous test case, except that we use a BEAM file +%% that was compiled by an R14 compiler to test backward compatibility. +fun_mfa_r14(Conf) when is_list(Conf) -> + Dir = ?config(data_dir, Conf), + MFile = fname(Dir, "fun_mfa_r14"), + + A = fun_mfa_r14, + {ok, _} = xref:start(s), + {ok, A} = xref:add_module(s, MFile, {warnings,false}), + {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, + {{{A,t,0},{A,t,0}},[6]}, + {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, + {{{A,t1,0},{A,t,0}},[10]}, + {{{A,t2,0},{A,t,0}},[14]}, + {{{A,t3,0},{A,t3,0}},[17]}]} = + xref:q(s, "(Lin) E"), + + ok = check_state(s), + xref:stop(s), + + ok. + +%% fun M:F/A with varibles. +fun_mfa_vars(Conf) when is_list(Conf) -> + Dir = ?copydir, + File = fname(Dir, "fun_mfa_vars.erl"), + MFile = fname(Dir, "fun_mfa_vars"), + Beam = fname(Dir, "fun_mfa_vars.beam"), + Test = <<"-module(fun_mfa_vars). + + -export([t/1, t1/1, t2/3]). + + t(Mod) -> + F = fun Mod:bar/2, + (F)(a, b). + + t1(Name) -> + F = fun ?MODULE:Name/1, + (F)(a). + + t2(Mod, Name, Arity) -> + F = fun Mod:Name/Arity, + (F)(a). + + t3(Arity) -> + F = fun ?MODULE:t/Arity, + (F)(1, 2, 3). + + t4(Mod, Name) -> + F = fun Mod:Name/3, + (F)(a, b, c). + + t5(Mod, Arity) -> + F = fun Mod:t/Arity, + (F)(). + ">>, + + ok = file:write_file(File, Test), + A = fun_mfa_vars, + {ok, A} = compile:file(File, [report,debug_info,{outdir,Dir}]), + {ok, _} = xref:start(s), + {ok, A} = xref:add_module(s, MFile, {warnings,false}), + {ok, [{{{A,t,1},{'$M_EXPR','$F_EXPR',2}},[7]}, + {{{A,t,1},{'$M_EXPR',bar,2}},[6]}, + {{{A,t1,1},{'$M_EXPR','$F_EXPR',1}},[11]}, + {{{A,t1,1},{A,'$F_EXPR',1}},[10]}, + {{{A,t2,3},{'$M_EXPR','$F_EXPR',-1}},[14]}, + {{{A,t2,3},{'$M_EXPR','$F_EXPR',1}},[15]}, + {{{A,t3,1},{'$M_EXPR','$F_EXPR',3}},[19]}, + {{{A,t3,1},{fun_mfa_vars,t,-1}},[18]}, + {{{A,t4,2},{'$M_EXPR','$F_EXPR',3}},[22,23]}, + {{{A,t5,2},{'$M_EXPR','$F_EXPR',0}},[27]}, + {{{A,t5,2},{'$M_EXPR',t,-1}},[26]}]} = + xref:q(s, "(Lin) E"), + + ok = check_state(s), + xref:stop(s), + + ok = file:delete(File), + ok = file:delete(Beam), + ok. + qlc(suite) -> []; qlc(doc) -> ["OTP-5195: A bug fix when using qlc:q/1,2."]; qlc(Conf) when is_list(Conf) -> diff --git a/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam Binary files differnew file mode 100644 index 0000000000..4645525690 --- /dev/null +++ b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam diff --git a/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl new file mode 100644 index 0000000000..293bd83a8b --- /dev/null +++ b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl @@ -0,0 +1,18 @@ +-module(fun_mfa_r14). + +-export([t/0, t1/0, t2/0, t3/0]). + +t() -> + F = fun ?MODULE:t/0, + (F)(). + +t1() -> + F = fun t/0, + (F)(). + +t2() -> + fun ?MODULE:t/0(). + +t3() -> + fun t3/0(). + diff --git a/lib/tv/doc/src/Makefile b/lib/tv/doc/src/Makefile index f30e0307a9..5a41b28d48 100644 --- a/lib/tv/doc/src/Makefile +++ b/lib/tv/doc/src/Makefile @@ -26,14 +26,6 @@ VSN=$(TV_VSN) APPLICATION=tv # ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -ifndef DOCSUPPORT -include make.dep -endif - -# ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) @@ -89,32 +81,10 @@ EXTRA_FILES = \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) -ifdef DOCSUPPORT - HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf -else - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ - $(XML_APPLICATION_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = tv-$(VSN).pdf -TOP_PS_FILE = tv-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi ../../vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -127,8 +97,6 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -ifdef DOCSUPPORT - docs: pdf html man $(TOP_PDF_FILE): $(XML_FILES) @@ -144,31 +112,6 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ -else - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html gifs man -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) gifs - -clean clean_docs clean_tex: - rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) - rm -f $(HTML_FILES) $(MAN3_FILES) - rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) - rm -f errs core *~ $(LATEX_CLEAN) -endif - man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -181,8 +124,6 @@ debug opt: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifdef DOCSUPPORT - release_docs_spec: docs $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf @@ -193,29 +134,5 @@ release_docs_spec: docs $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -else - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 -endif -endif - -endif - release_spec: diff --git a/lib/tv/doc/src/make.dep b/lib/tv/doc/src/make.dep deleted file mode 100644 index 8437e320c6..0000000000 --- a/lib/tv/doc/src/make.dep +++ /dev/null @@ -1,32 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex table_visualizer_chapter.tex \ - tv.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -# ---------------------------------------------------- -# Pictures that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: info_window.ps set_poll_int.ps tv_create_table.ps \ - tv_record_editor_mnesia.ps tv_row_marked.ps \ - tv_row_marked_popup.ps tv_search_result.ps \ - tv_search_window.ps tv_start.ps tv_start_mnesia.ps \ - tv_start_other_node.ps tv_start_pid_sorted.ps \ - tv_start_system.ps tv_start_system_unreadable.ps \ - tv_table_browser.ps tv_table_browser_updated.ps - diff --git a/lib/webtool/doc/src/make.dep b/lib/webtool/doc/src/make.dep deleted file mode 100644 index 87526b3f73..0000000000 --- a/lib/webtool/doc/src/make.dep +++ /dev/null @@ -1,20 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex start_webtool.tex \ - webtool.tex webtool_chapter.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/wx/api_gen/wx_doxygen.conf b/lib/wx/api_gen/wx_doxygen.conf index df150fd154..829702cbbf 100644 --- a/lib/wx/api_gen/wx_doxygen.conf +++ b/lib/wx/api_gen/wx_doxygen.conf @@ -251,6 +251,7 @@ PREDEFINED = \ wxUSE_DATAOBJ=1 \ wxUSE_SLIDER=1 \ wxUSE_CLIPBOARD=1 \ + wxUSE_SYSTEM_OPTIONS=1 \ wxABI_VERSION=20809 \ __WXGTK24__=1 \ __WXGTK20__=1 \ diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl index 4632fdbffe..1b4c32db24 100644 --- a/lib/wx/api_gen/wx_gen_cpp.erl +++ b/lib/wx/api_gen/wx_gen_cpp.erl @@ -1034,6 +1034,7 @@ gen_macros() -> w("#include <wx/html/htmlwin.h>~n"), w("#include <wx/html/htmlcell.h>~n"), w("#include <wx/filename.h>~n"), + w("#include <wx/sysopt.h>~n"), w("~n~n", []), w("#ifndef wxICON_DEFAULT_BITMAP_TYPE~n",[]), diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl index e882ae87ca..5d73d93ead 100644 --- a/lib/wx/api_gen/wx_gen_erl.erl +++ b/lib/wx/api_gen/wx_gen_erl.erl @@ -830,7 +830,7 @@ doc_arg_type3(#type{base={comp,_,Tup}}) -> Doc = fun({int,V}) -> V ++ "::integer()"; ({double,V}) -> V ++ "::float()" end, - "{" ++ args(Doc, ",", Tup) ++ "}"; + "{" ++ args(Doc, ", ", Tup) ++ "}"; doc_arg_type3(T) -> ?error({unknown_type,T}). doc_return_types(T, Ps) -> @@ -839,9 +839,9 @@ doc_return_types2(void, []) -> "ok"; doc_return_types2(void, [#param{type=T}]) -> doc_arg_type2(T); doc_return_types2(T, []) -> doc_arg_type2(T); doc_return_types2(void, Ps) -> - "{" ++ args(fun doc_arg_type/1,",",Ps) ++ "}"; + "{" ++ args(fun doc_arg_type/1,", ",Ps) ++ "}"; doc_return_types2(T, Ps) -> - "{" ++ doc_arg_type2(T) ++ "," ++ args(fun doc_arg_type/1,",",Ps) ++ "}". + "{" ++ doc_arg_type2(T) ++ ", " ++ args(fun doc_arg_type/1,", ",Ps) ++ "}". break(xhtml) -> "<br />"; break(_) -> "". diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf index 8ee4451057..ff618faf04 100644 --- a/lib/wx/api_gen/wxapi.conf +++ b/lib/wx/api_gen/wxapi.conf @@ -1755,6 +1755,9 @@ 'GetColour','GetFont','GetMetric','GetScreenType' ]}. +{class, wxSystemOptions, object, [], + ['GetOption', 'GetOptionInt', 'HasOption', 'IsFalse', 'SetOption']}. + {class, wxAuiNotebookEvent, wxNotifyEvent, [{acc, [{old_selection, "GetOldSelection()"}, {selection, "GetSelection()"}, diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in index 69418f62ef..ae5a149d14 100644 --- a/lib/wx/c_src/Makefile.in +++ b/lib/wx/c_src/Makefile.in @@ -31,6 +31,8 @@ override TYPE=opt endif SO_EXT = @SO_EXT@ +OBJC_CC=@OBJC_CC@ +OBJC_CFLAGS=@OBJC_CFLAGS@ GENERAL = wxe_driver wxe_ps_init wxe_impl wxePrintout wxe_return wxe_gl GENERAL_H = wxe_driver.h wxe_impl.h wxe_return.h @@ -116,6 +118,7 @@ endif GL_LIBS = @GL_LIBS@ CC_O = $(CC) -c $(CFLAGS) $(WX_CFLAGS) $(COMMON_CFLAGS) +OBJC_CC_O = $(OBJC_CC) -c $(CFLAGS) $(OBJC_CFLAGS) $(WX_CFLAGS) $(COMMON_CFLAGS) CPP_O = $(CPP) -c $(CXX_FLAGS) $(WX_CXX_FLAGS) $(COMMON_CFLAGS) # Targets @@ -152,6 +155,10 @@ $(SYS_TYPE)/%.o: %.c mkdir -p $(SYS_TYPE) $(CC_O) $< -o $@ +$(SYS_TYPE)/wxe_ps_init.o: wxe_ps_init.c + mkdir -p $(SYS_TYPE) + $(OBJC_CC_O) $< -o $@ + $(SYS_TYPE)/%.o: gen/%.cpp mkdir -p $(SYS_TYPE) $(CPP_O) $< -o $@ diff --git a/lib/wx/c_src/egl_impl.cpp b/lib/wx/c_src/egl_impl.cpp index 6d873abc44..1379f07523 100644 --- a/lib/wx/c_src/egl_impl.cpp +++ b/lib/wx/c_src/egl_impl.cpp @@ -70,8 +70,8 @@ typedef char DL_CHAR; # define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib" # define OPENGLU_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib" # else -# define OPENGL_LIB "libGL.so" -# define OPENGLU_LIB "libGLU.so" +# define OPENGL_LIB "libGL.so.1" +# define OPENGLU_LIB "libGLU.so.1" # endif #endif extern "C" { @@ -121,7 +121,7 @@ int load_gl_functions() { } } } - dlclose(LIBhandle); + // dlclose(LIBhandle); // fprintf(stderr, "OPENGL library is loaded\r\n"); } else { fprintf(stderr, "Could NOT load OpenGL library: %s\r\n", DLName); @@ -150,7 +150,7 @@ int load_gl_functions() { } } } - dlclose(LIBhandle); + // dlclose(LIBhandle); // fprintf(stderr, "GLU library is loaded\r\n"); } else { fprintf(stderr, "Could NOT load OpenGL GLU library: %s\r\n", DLName); @@ -195,7 +195,7 @@ egl_ogla_error(GLenum errorCode) // msg.Printf(wxT("Tesselation error: %d: "), (int)errorCode); // msg += wxString::FromAscii((char *) err); // send_msg("error", &msg); - fprintf(stderr, "Tesselation error: %d\r\n", (int) errorCode); + fprintf(stderr, "Tesselation error: %d: %s\r\n", (int) errorCode, err); } void CALLBACK @@ -250,7 +250,7 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) int *vertices; int num_vertices; GLdouble *n; - int n_pos, AP, res; + int n_pos, AP; num_vertices = * (int *) buff; buff += 8; /* Align */ n = (double *) buff; buff += 8*3; @@ -293,7 +293,7 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin} rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple - res = driver_send_term(port,caller,rt,AP); + driver_send_term(port,caller,rt,AP); /* fprintf(stderr, "List %d: %d %d %d \r\n", */ /* res, */ /* n_pos, */ diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp index b9769318af..cda98bfc3f 100644 --- a/lib/wx/c_src/gen/wxe_events.cpp +++ b/lib/wx/c_src/gen/wxe_events.cpp @@ -266,41 +266,41 @@ void initEventTable() {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 218, "command_splitter_doubleclicked"}, {wxEVT_COMMAND_SPLITTER_UNSPLIT, 218, "command_splitter_unsplit"}, {wxEVT_COMMAND_HTML_LINK_CLICKED, 220, "command_html_link_clicked"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 222, "command_auinotebook_page_close"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 222, "command_auinotebook_page_changed"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 222, "command_auinotebook_page_changing"}, - {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 222, "command_auinotebook_button"}, - {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 222, "command_auinotebook_begin_drag"}, - {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 222, "command_auinotebook_end_drag"}, - {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 222, "command_auinotebook_drag_motion"}, - {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 222, "command_auinotebook_allow_dnd"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 223, "command_auinotebook_page_close"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 223, "command_auinotebook_page_changed"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 223, "command_auinotebook_page_changing"}, + {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 223, "command_auinotebook_button"}, + {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 223, "command_auinotebook_begin_drag"}, + {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 223, "command_auinotebook_end_drag"}, + {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 223, "command_auinotebook_drag_motion"}, + {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 223, "command_auinotebook_allow_dnd"}, #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 222, "command_auinotebook_tab_middle_down"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 223, "command_auinotebook_tab_middle_down"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 222, "command_auinotebook_tab_middle_up"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 223, "command_auinotebook_tab_middle_up"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 222, "command_auinotebook_tab_right_down"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 223, "command_auinotebook_tab_right_down"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 222, "command_auinotebook_tab_right_up"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 223, "command_auinotebook_tab_right_up"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 222, "command_auinotebook_page_closed"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 223, "command_auinotebook_page_closed"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 222, "command_auinotebook_drag_done"}, + {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 223, "command_auinotebook_drag_done"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 222, "command_auinotebook_bg_dclick"}, + {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 223, "command_auinotebook_bg_dclick"}, #endif - {wxEVT_AUI_PANE_BUTTON, 223, "aui_pane_button"}, - {wxEVT_AUI_PANE_CLOSE, 223, "aui_pane_close"}, - {wxEVT_AUI_PANE_MAXIMIZE, 223, "aui_pane_maximize"}, - {wxEVT_AUI_PANE_RESTORE, 223, "aui_pane_restore"}, - {wxEVT_AUI_RENDER, 223, "aui_render"}, - {wxEVT_AUI_FIND_MANAGER, 223, "aui_find_manager"}, + {wxEVT_AUI_PANE_BUTTON, 224, "aui_pane_button"}, + {wxEVT_AUI_PANE_CLOSE, 224, "aui_pane_close"}, + {wxEVT_AUI_PANE_MAXIMIZE, 224, "aui_pane_maximize"}, + {wxEVT_AUI_PANE_RESTORE, 224, "aui_pane_restore"}, + {wxEVT_AUI_RENDER, 224, "aui_render"}, + {wxEVT_AUI_FIND_MANAGER, 224, "aui_find_manager"}, {-1, 0, } }; for(int i=0; event_types[i].ev_type != -1; i++) { @@ -778,7 +778,7 @@ case 220: {// wxHtmlLinkEvent rt.addTupleCount(3); break; } -case 222: {// wxAuiNotebookEvent +case 223: {// wxAuiNotebookEvent wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event; wxAuiNotebook * GetDragSource = ev->GetDragSource(); evClass = (char*)"wxAuiNotebookEvent"; @@ -790,7 +790,7 @@ case 222: {// wxAuiNotebookEvent rt.addTupleCount(5); break; } -case 223: {// wxAuiManagerEvent +case 224: {// wxAuiManagerEvent wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event; wxAuiManager * GetManager = ev->GetManager(); wxAuiPaneInfo * GetPane = ev->GetPane(); diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index afef2990b4..f456bd3287 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -31160,6 +31160,56 @@ case wxSystemSettings_GetScreenType: { // wxSystemSettings::GetScreenType rt.addInt(Result); break; } +case wxSystemOptions_GetOption: { // wxSystemOptions::GetOption + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + wxString Result = wxSystemOptions::GetOption(name); + rt.add(Result); + break; +} +case wxSystemOptions_GetOptionInt: { // wxSystemOptions::GetOptionInt + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + int Result = wxSystemOptions::GetOptionInt(name); + rt.addInt(Result); + break; +} +case wxSystemOptions_HasOption: { // wxSystemOptions::HasOption + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + bool Result = wxSystemOptions::HasOption(name); + rt.addBool(Result); + break; +} +case wxSystemOptions_IsFalse: { // wxSystemOptions::IsFalse + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + bool Result = wxSystemOptions::IsFalse(name); + rt.addBool(Result); + break; +} +case wxSystemOptions_SetOption_2_1: { // wxSystemOptions::SetOption + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + int * valueLen = (int *) bp; bp += 4; + wxString value = wxString(bp, wxConvUTF8); + bp += *valueLen+((8-((4+ *valueLen) & 7)) & 7); + wxSystemOptions::SetOption(name,value); + break; +} +case wxSystemOptions_SetOption_2_0: { // wxSystemOptions::SetOption + int * nameLen = (int *) bp; bp += 4; + wxString name = wxString(bp, wxConvUTF8); + bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7); + int * value = (int *) bp; bp += 4; + wxSystemOptions::SetOption(name,(int) *value); + break; +} case wxAuiNotebookEvent_SetSelection: { // wxAuiNotebookEvent::SetSelection wxAuiNotebookEvent *This = (wxAuiNotebookEvent *) getPtr(bp,memenv); bp += 4; int * s = (int *) bp; bp += 4; @@ -31294,7 +31344,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto } case wxLogNull_new: { // wxLogNull::wxLogNull wxLogNull * Result = new wxLogNull(); - newPtr((void *) Result, 224, memenv); + newPtr((void *) Result, 225, memenv); rt.addRef(getRef((void *)Result,memenv), "wxLogNull"); break; } @@ -31347,7 +31397,7 @@ void WxeApp::delete_object(void *ptr, wxeRefData *refd) { case 212: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break; case 213: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break; case 214: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break; - case 224: delete (wxLogNull *) ptr; break; + case 225: delete (wxLogNull *) ptr; break; default: delete (wxObject *) ptr; }} diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h index be0481564f..ddc7c0155f 100644 --- a/lib/wx/c_src/gen/wxe_macros.h +++ b/lib/wx/c_src/gen/wxe_macros.h @@ -60,6 +60,7 @@ #include <wx/html/htmlwin.h> #include <wx/html/htmlcell.h> #include <wx/filename.h> +#include <wx/sysopt.h> #ifndef wxICON_DEFAULT_BITMAP_TYPE @@ -3318,25 +3319,31 @@ #define wxSystemSettings_GetFont 3489 #define wxSystemSettings_GetMetric 3490 #define wxSystemSettings_GetScreenType 3491 -#define wxAuiNotebookEvent_SetSelection 3492 -#define wxAuiNotebookEvent_GetSelection 3493 -#define wxAuiNotebookEvent_SetOldSelection 3494 -#define wxAuiNotebookEvent_GetOldSelection 3495 -#define wxAuiNotebookEvent_SetDragSource 3496 -#define wxAuiNotebookEvent_GetDragSource 3497 -#define wxAuiManagerEvent_SetManager 3498 -#define wxAuiManagerEvent_GetManager 3499 -#define wxAuiManagerEvent_SetPane 3500 -#define wxAuiManagerEvent_GetPane 3501 -#define wxAuiManagerEvent_SetButton 3502 -#define wxAuiManagerEvent_GetButton 3503 -#define wxAuiManagerEvent_SetDC 3504 -#define wxAuiManagerEvent_GetDC 3505 -#define wxAuiManagerEvent_Veto 3506 -#define wxAuiManagerEvent_GetVeto 3507 -#define wxAuiManagerEvent_SetCanVeto 3508 -#define wxAuiManagerEvent_CanVeto 3509 -#define wxLogNull_new 3510 -#define wxLogNull_destroy 3511 +#define wxSystemOptions_GetOption 3492 +#define wxSystemOptions_GetOptionInt 3493 +#define wxSystemOptions_HasOption 3494 +#define wxSystemOptions_IsFalse 3495 +#define wxSystemOptions_SetOption_2_1 3496 +#define wxSystemOptions_SetOption_2_0 3497 +#define wxAuiNotebookEvent_SetSelection 3498 +#define wxAuiNotebookEvent_GetSelection 3499 +#define wxAuiNotebookEvent_SetOldSelection 3500 +#define wxAuiNotebookEvent_GetOldSelection 3501 +#define wxAuiNotebookEvent_SetDragSource 3502 +#define wxAuiNotebookEvent_GetDragSource 3503 +#define wxAuiManagerEvent_SetManager 3504 +#define wxAuiManagerEvent_GetManager 3505 +#define wxAuiManagerEvent_SetPane 3506 +#define wxAuiManagerEvent_GetPane 3507 +#define wxAuiManagerEvent_SetButton 3508 +#define wxAuiManagerEvent_GetButton 3509 +#define wxAuiManagerEvent_SetDC 3510 +#define wxAuiManagerEvent_GetDC 3511 +#define wxAuiManagerEvent_Veto 3512 +#define wxAuiManagerEvent_GetVeto 3513 +#define wxAuiManagerEvent_SetCanVeto 3514 +#define wxAuiManagerEvent_CanVeto 3515 +#define wxLogNull_new 3516 +#define wxLogNull_destroy 3517 diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index e430fbc7a2..69fcd4e362 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -331,9 +331,9 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) driver_monitor_process(port, process, &monitor); // Should we be able to handle commands when recursing? probably erl_drv_mutex_lock(wxe_batch_locker_m); - // fprintf(stderr, "\r\nCB EV Start ");fflush(stderr); + //fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr); app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process); - // fprintf(stderr, ".. done \r\n");fflush(stderr); + //fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr); wxe_batch_caller = 0; erl_drv_mutex_unlock(wxe_batch_locker_m); driver_demonitor_process(port, &monitor); @@ -430,8 +430,9 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) wxeCommand *event = (wxeCommand *)node->GetData(); wxeMemEnv *memenv = getMemEnv(event->port); batch->Erase(node); + // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller); if(event->caller == process || // Callbacks from CB process only - event->op == WXE_CB_START || // Recursive event callback allow + event->op == WXE_CB_START || // Event callback start change process // Allow connect_cb during CB i.e. msg from wxe_server. (memenv && event->caller == memenv->owner)) { @@ -453,6 +454,7 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) break; default: erl_drv_mutex_unlock(wxe_batch_locker_m); + size_t start=temp->GetCount(); if(event->op < OPENGL_START) { // fprintf(stderr, " cb %d \r\n", event->op); wxe_dispatch(*event); @@ -460,9 +462,23 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) gl_dispatch(event->op,event->buffer,event->caller,event->bin); } erl_drv_mutex_lock(wxe_batch_locker_m); - break; + if(temp->GetCount() > start) { + // We have recursed dispatch_cb and messages for this + // callback may be saved on temp list move them + // to orig list + for(wxList::compatibility_iterator node = temp->Item(start); + node; + node = node->GetNext()) { + wxeCommand *ev = (wxeCommand *)node->GetData(); + if(ev->caller == process) { + batch->Append(ev); + temp->Erase(node); + } + } + } if(callback_returned) return; + break; } delete event; } else { diff --git a/lib/wx/configure.in b/lib/wx/configure.in index f7128db23a..78c3f0d3d2 100755 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -138,10 +138,65 @@ esac PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT" +OBJC_CC=$CC +OBJC_CFLAGS="" + dnl NOTE: CPPFLAGS will be included in CFLAGS at the end case $host_os in darwin*) - C_ONLY_FLAGS="-ObjC" + AC_MSG_CHECKING([if compiler accepts -ObjC]) + saved_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -ObjC" + AC_TRY_COMPILE([],[;], accept_objc_flag=true, accept_objc_flag=false) + if test "X$accept_objc_flag" = "Xtrue"; then + AC_MSG_RESULT([yes]) + C_ONLY_FLAGS="-ObjC" + else + dnl We are probebly trying to build with a non-Apple gcc, + dnl which is good as long as we do not try to build Cocoa + dnl code. We need an Apple compiler for just that (Objective C) + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([for a Cocoa compliant Objective C compiler]) + SEARCHFOR="" + save_IFS=$IFS + IFS=: + set $PATH + IFS=$save_IFS + while test X"$1" != X""; do + dnl Add all possible paths to a real apple gcc + SEARCHFOR="$1/gcc-apple-4.2 $SEARCHFOR" + shift + done + dnl Add LLVM compilers, they will work in this case + SEARCHFOR="/usr/bin/clang /usr/bin/gcc $SEARCHFOR" + APPLE_CC="" + dnl SEARCHFOR is reversed, so we want to find the last existing + dnl executable in the list + for x in $SEARCHFOR; do + if test -x $x; then + APPLE_CC=$x + fi + done + if test X$APPLE_CC = X; then + AC_MSG_RESULT([no]) + dnl Complete failure, we cannot build Cocoa code + if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then + AC_MSG_ERROR([Can not find compiler to compile Cocoa applications]) + else + echo "Can not find compiler to compile Cocoa applications" > ./CONF_INFO + WXERL_CAN_BUILD_DRIVER=false + AC_MSG_WARN([Can not find compiler to compile Cocoa applications]) + fi + WXERL_CAN_BUILD_DRIVER=false + else + dnl We think we found an Apple compiler and will add + dnl Apple specific options + AC_MSG_RESULT($APPLE_CC) + OBJC_CC=$APPLE_CC + OBJC_CFLAGS="-ObjC" + fi + fi + CFLAGS=$saved_CFLAGS CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" ;; mingw32) @@ -159,10 +214,29 @@ case $host_os in ;; esac +AC_SUBST(OBJC_CC) +AC_SUBST(OBJC_CFLAGS) + case $host_os in darwin*) - CFLAGS="-no-cpp-precomp $CFLAGS" + AC_TRY_COMPILE([],[ + #if __GNUC__ >= 4 + ; + #else + #error old or no gcc + #endif + ], + gcc_need_no_cpp_precomp=no, + gcc_need_no_cpp_precomp=yes) + + if test x$gcc_need_no_cpp_precomp = xyes; then + CFLAGS="-no-cpp-precomp $CFLAGS" + fi LDFLAGS="-bundle -flat_namespace -undefined warning -fPIC $LDFLAGS" + # Check sizof_void_p as future will hold 64bit MacOS wx + if test $ac_cv_sizeof_void_p = 4; then + LDFLAGS="-m32 $LDFLAGS" + fi GL_LIBS="-framework OpenGL" ;; win32) diff --git a/lib/wx/doc/src/make.dep b/lib/wx/doc/src/make.dep deleted file mode 100644 index 91001be438..0000000000 --- a/lib/wx/doc/src/make.dep +++ /dev/null @@ -1,13 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex chapter.tex part.tex - diff --git a/lib/wx/examples/demo/Makefile b/lib/wx/examples/demo/Makefile index 98d7c6a130..8afa0e780e 100755..100644 --- a/lib/wx/examples/demo/Makefile +++ b/lib/wx/examples/demo/Makefile @@ -80,7 +80,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk docs: -release_spec: +release_spec: opt $(INSTALL_DIR) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR) diff --git a/lib/wx/examples/simple/Makefile b/lib/wx/examples/simple/Makefile index 41f0b46eb1..66f5952f0d 100644 --- a/lib/wx/examples/simple/Makefile +++ b/lib/wx/examples/simple/Makefile @@ -51,7 +51,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk docs: -release_spec: +release_spec: opt $(INSTALL_DIR) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR) $(INSTALL_DATA) copy.xpm sample.xpm $(TESTTARGETS) $(EXRELSYSDIR) diff --git a/lib/wx/examples/simple/hello.erl b/lib/wx/examples/simple/hello.erl index dc845ddfbb..dc845ddfbb 100755..100644 --- a/lib/wx/examples/simple/hello.erl +++ b/lib/wx/examples/simple/hello.erl diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl index d573fcf13a..d573fcf13a 100755..100644 --- a/lib/wx/examples/simple/menu.erl +++ b/lib/wx/examples/simple/menu.erl diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl index dca4adc643..dca4adc643 100755..100644 --- a/lib/wx/examples/simple/minimal.erl +++ b/lib/wx/examples/simple/minimal.erl diff --git a/lib/wx/examples/simple/sample.xpm b/lib/wx/examples/simple/sample.xpm index 3263b15f8a..3263b15f8a 100755..100644 --- a/lib/wx/examples/simple/sample.xpm +++ b/lib/wx/examples/simple/sample.xpm diff --git a/lib/wx/examples/sudoku/Makefile b/lib/wx/examples/sudoku/Makefile index b86c654fdd..33725756b7 100755..100644 --- a/lib/wx/examples/sudoku/Makefile +++ b/lib/wx/examples/sudoku/Makefile @@ -51,7 +51,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk docs: -release_spec: +release_spec: opt $(INSTALL_DIR) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTSRC) sudoku.hrl $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR) diff --git a/lib/wx/examples/sudoku/sudoku.erl b/lib/wx/examples/sudoku/sudoku.erl index 01caeb9524..01caeb9524 100755..100644 --- a/lib/wx/examples/sudoku/sudoku.erl +++ b/lib/wx/examples/sudoku/sudoku.erl diff --git a/lib/wx/examples/sudoku/sudoku.hrl b/lib/wx/examples/sudoku/sudoku.hrl index 775b563bdc..775b563bdc 100755..100644 --- a/lib/wx/examples/sudoku/sudoku.hrl +++ b/lib/wx/examples/sudoku/sudoku.hrl diff --git a/lib/wx/examples/sudoku/sudoku_board.erl b/lib/wx/examples/sudoku/sudoku_board.erl index 756837582f..756837582f 100755..100644 --- a/lib/wx/examples/sudoku/sudoku_board.erl +++ b/lib/wx/examples/sudoku/sudoku_board.erl diff --git a/lib/wx/examples/sudoku/sudoku_game.erl b/lib/wx/examples/sudoku/sudoku_game.erl index 470aee0e3b..470aee0e3b 100755..100644 --- a/lib/wx/examples/sudoku/sudoku_game.erl +++ b/lib/wx/examples/sudoku/sudoku_game.erl diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl index 4aaecfe086..4aaecfe086 100755..100644 --- a/lib/wx/examples/sudoku/sudoku_gui.erl +++ b/lib/wx/examples/sudoku/sudoku_gui.erl diff --git a/lib/wx/examples/xrc/Makefile b/lib/wx/examples/xrc/Makefile index 1dfaae9689..aba58e0d0f 100755..100644 --- a/lib/wx/examples/xrc/Makefile +++ b/lib/wx/examples/xrc/Makefile @@ -28,7 +28,8 @@ TESTMODS = xrc TESTTARGETS = $(TESTMODS:%=%.beam) TESTSRC = $(TESTMODS:%=%.erl) -RESOURCEFILES = appicon.ico basicdlg.xpm custclas.xpm fileopen.gif menu.xrc \ +RESOURCEFILES = \ + appicon.ico basicdlg.xpm custclas.xpm fileopen.gif menu.xrc \ resource.xrc uncenter.xpm variable.xrc appicon.xpm basicdlg.xrc \ custclas.xrc filesave.gif platform.xpm stop.xpm uncenter.xrc \ artprov.xpm controls.xpm derivdlg.xpm frame.xrc platform.xrc \ @@ -59,7 +60,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk docs: -release_spec: +release_spec: opt $(INSTALL_DIR) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR) $(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR) diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl index 8659b71985..029b9a88df 100644 --- a/lib/wx/include/wx.hrl +++ b/lib/wx/include/wx.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,12 +36,12 @@ %% Callback event: {@link wxNavigationKeyEvent} -record(wxNavigationKey,{type, flags,focus}). -%% @type wxSash() = #wxSash{type=wxEventType(),edge=WxSashEdgePosition,dragRect={X::integer(),Y::integer(),W::integer(),H::integer()},dragStatus=WxSashDragStatus}. +%% @type wxSash() = #wxSash{type=wxEventType(),edge=WxSashEdgePosition,dragRect={X::integer(), Y::integer(), W::integer(), H::integer()},dragStatus=WxSashDragStatus}. %% <dl><dt>EventType:</dt> <dd><em>sash_dragged</em></dd></dl> %% Callback event: {@link wxSashEvent} -record(wxSash,{type, edge,dragRect,dragStatus}). -%% @type wxList() = #wxList{type=wxEventType(),code=integer(),oldItemIndex=integer(),itemIndex=integer(),col=integer(),pointDrag={X::integer(),Y::integer()}}. +%% @type wxList() = #wxList{type=wxEventType(),code=integer(),oldItemIndex=integer(),itemIndex=integer(),col=integer(),pointDrag={X::integer(), Y::integer()}}. %% <dl><dt>EventType:</dt> <dd><em>command_list_begin_drag</em>, <em>command_list_begin_rdrag</em>, <em>command_list_begin_label_edit</em>, <em>command_list_end_label_edit</em>, <em>command_list_delete_item</em>, <em>command_list_delete_all_items</em>, <em>command_list_key_down</em>, <em>command_list_insert_item</em>, <em>command_list_col_click</em>, <em>command_list_col_right_click</em>, <em>command_list_col_begin_drag</em>, <em>command_list_col_dragging</em>, <em>command_list_col_end_drag</em>, <em>command_list_item_selected</em>, <em>command_list_item_deselected</em>, <em>command_list_item_right_click</em>, <em>command_list_item_middle_click</em>, <em>command_list_item_activated</em>, <em>command_list_item_focused</em>, <em>command_list_cache_hint</em></dd></dl> %% Callback event: {@link wxListEvent} -record(wxList,{type, code,oldItemIndex,itemIndex,col,pointDrag}). @@ -186,7 +186,7 @@ %% Callback event: {@link wxUpdateUIEvent} -record(wxUpdateUI, {type}). -%% @type wxSize() = #wxSize{type=wxEventType(),size={W::integer(),H::integer()},rect={X::integer(),Y::integer(),W::integer(),H::integer()}}. +%% @type wxSize() = #wxSize{type=wxEventType(),size={W::integer(), H::integer()},rect={X::integer(), Y::integer(), W::integer(), H::integer()}}. %% <dl><dt>EventType:</dt> <dd><em>size</em></dd></dl> %% Callback event: {@link wxSizeEvent} -record(wxSize,{type, size,rect}). @@ -261,7 +261,7 @@ %% Callback event: {@link wxColourPickerEvent} -record(wxColourPicker,{type, colour}). -%% @type wxTree() = #wxTree{type=wxEventType(),item=integer(),itemOld=integer(),pointDrag={X::integer(),Y::integer()}}. +%% @type wxTree() = #wxTree{type=wxEventType(),item=integer(),itemOld=integer(),pointDrag={X::integer(), Y::integer()}}. %% <dl><dt>EventType:</dt> <dd><em>command_tree_begin_drag</em>, <em>command_tree_begin_rdrag</em>, <em>command_tree_begin_label_edit</em>, <em>command_tree_end_label_edit</em>, <em>command_tree_delete_item</em>, <em>command_tree_get_info</em>, <em>command_tree_set_info</em>, <em>command_tree_item_expanded</em>, <em>command_tree_item_expanding</em>, <em>command_tree_item_collapsed</em>, <em>command_tree_item_collapsing</em>, <em>command_tree_sel_changed</em>, <em>command_tree_sel_changing</em>, <em>command_tree_key_down</em>, <em>command_tree_item_activated</em>, <em>command_tree_item_right_click</em>, <em>command_tree_item_middle_click</em>, <em>command_tree_end_drag</em>, <em>command_tree_state_image_click</em>, <em>command_tree_item_gettooltip</em>, <em>command_tree_item_menu</em></dd></dl> %% Callback event: {@link wxTreeEvent} -record(wxTree,{type, item,itemOld,pointDrag}). diff --git a/lib/wx/src/gen/wxArtProvider.erl b/lib/wx/src/gen/wxArtProvider.erl index 7a45b0d79d..1955bd2e29 100644 --- a/lib/wx/src/gen/wxArtProvider.erl +++ b/lib/wx/src/gen/wxArtProvider.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,7 +39,7 @@ getBitmap(Id) getBitmap(Id, []). %% @spec (Id::string(), [Option]) -> wxBitmap:wxBitmap() -%% Option = {client, string()} | {size, {W::integer(),H::integer()}} +%% Option = {client, string()} | {size, {W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxartprovider.html#wxartprovidergetbitmap">external documentation</a>. getBitmap(Id, Options) when is_list(Id),is_list(Options) -> @@ -58,7 +58,7 @@ getIcon(Id) getIcon(Id, []). %% @spec (Id::string(), [Option]) -> wxIcon:wxIcon() -%% Option = {client, string()} | {size, {W::integer(),H::integer()}} +%% Option = {client, string()} | {size, {W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxartprovider.html#wxartprovidergeticon">external documentation</a>. getIcon(Id, Options) when is_list(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxAuiManager.erl b/lib/wx/src/gen/wxAuiManager.erl index ad0af6652d..893867cec1 100644 --- a/lib/wx/src/gen/wxAuiManager.erl +++ b/lib/wx/src/gen/wxAuiManager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ addPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_ wxe_util:call(?wxAuiManager_AddPane_2_1, <<ThisRef:32/?UI,WindowRef:32/?UI,Pane_infoRef:32/?UI>>). -%% @spec (This::wxAuiManager(), Window::wxWindow:wxWindow(), Pane_info::wxAuiPaneInfo:wxAuiPaneInfo(), Drop_pos::{X::integer(),Y::integer()}) -> bool() +%% @spec (This::wxAuiManager(), Window::wxWindow:wxWindow(), Pane_info::wxAuiPaneInfo:wxAuiPaneInfo(), Drop_pos::{X::integer(), Y::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanageraddpane">external documentation</a>. addPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_ref{type=Pane_infoT,ref=Pane_infoRef},{Drop_posX,Drop_posY}) when is_integer(Drop_posX),is_integer(Drop_posY) -> @@ -123,7 +123,7 @@ getArtProvider(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxAuiManager_GetArtProvider, <<ThisRef:32/?UI>>). -%% @spec (This::wxAuiManager()) -> {Width_pct::float(),Height_pct::float()} +%% @spec (This::wxAuiManager()) -> {Width_pct::float(), Height_pct::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanagergetdocksizeconstraint">external documentation</a>. getDockSizeConstraint(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxAuiManager), @@ -275,7 +275,7 @@ setManagedWindow(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=Managed_wndT,ref=M wxe_util:cast(?wxAuiManager_SetManagedWindow, <<ThisRef:32/?UI,Managed_wndRef:32/?UI>>). -%% @spec (This::wxAuiManager(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxAuiManager(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanagershowhint">external documentation</a>. showHint(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> diff --git a/lib/wx/src/gen/wxAuiNotebook.erl b/lib/wx/src/gen/wxAuiNotebook.erl index 5d486aeaa2..5862bb26c7 100644 --- a/lib/wx/src/gen/wxAuiNotebook.erl +++ b/lib/wx/src/gen/wxAuiNotebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -92,7 +92,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxAuiNotebook() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebookwxauinotebook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -134,7 +134,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxAuiNotebook(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -289,7 +289,7 @@ setTabCtrlHeight(#wx_ref{type=ThisT,ref=ThisRef},Height) wxe_util:cast(?wxAuiNotebook_SetTabCtrlHeight, <<ThisRef:32/?UI,Height:32/?UI>>). -%% @spec (This::wxAuiNotebook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxAuiNotebook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebooksetuniformbitmapsize">external documentation</a>. setUniformBitmapSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxAuiPaneInfo.erl b/lib/wx/src/gen/wxAuiPaneInfo.erl index 7b1401b069..b15f91c675 100644 --- a/lib/wx/src/gen/wxAuiPaneInfo.erl +++ b/lib/wx/src/gen/wxAuiPaneInfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -60,7 +60,7 @@ new(#wx_ref{type=CT,ref=CRef}) -> wxe_util:construct(?wxAuiPaneInfo_new_1, <<CRef:32/?UI>>). -%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo() +%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfobestsize">external documentation</a>. bestSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -250,7 +250,7 @@ floatable(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxAuiPaneInfo_Floatable, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxAuiPaneInfo(), Pos::{X::integer(),Y::integer()}) -> wxAuiPaneInfo() +%% @spec (This::wxAuiPaneInfo(), Pos::{X::integer(), Y::integer()}) -> wxAuiPaneInfo() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfofloatingposition">external documentation</a>. floatingPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) when is_integer(PosX),is_integer(PosY) -> @@ -266,7 +266,7 @@ floatingPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:call(?wxAuiPaneInfo_FloatingPosition_2, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo() +%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfofloatingsize">external documentation</a>. floatingSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -513,7 +513,7 @@ leftDockable(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxAuiPaneInfo_LeftDockable, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo() +%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfomaxsize">external documentation</a>. maxSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -547,7 +547,7 @@ maximizeButton(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxAuiPaneInfo_MaximizeButton, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo() +%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfominsize">external documentation</a>. minSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxBitmap.erl b/lib/wx/src/gen/wxBitmap.erl index 53c57e4393..bd2f83c6eb 100644 --- a/lib/wx/src/gen/wxBitmap.erl +++ b/lib/wx/src/gen/wxBitmap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -194,7 +194,7 @@ getWidth(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxBitmap_GetWidth, <<ThisRef:32/?UI>>). -%% @spec (This::wxBitmap(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> wxBitmap() +%% @spec (This::wxBitmap(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> wxBitmap() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmap.html#wxbitmapgetsubbitmap">external documentation</a>. getSubBitmap(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> diff --git a/lib/wx/src/gen/wxBitmapButton.erl b/lib/wx/src/gen/wxBitmapButton.erl index 0c187bf1c1..d2353466e7 100644 --- a/lib/wx/src/gen/wxBitmapButton.erl +++ b/lib/wx/src/gen/wxBitmapButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -92,7 +92,7 @@ new(Parent,Id,Bitmap) new(Parent,Id,Bitmap, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Bitmap::wxBitmap:wxBitmap(), [Option]) -> wxBitmapButton() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmapbutton.html#wxbitmapbuttonwxbitmapbutton">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Id),is_list(Options) -> @@ -114,7 +114,7 @@ create(This,Parent,Id,Bitmap) create(This,Parent,Id,Bitmap, []). %% @spec (This::wxBitmapButton(), Parent::wxWindow:wxWindow(), Id::integer(), Bitmap::wxBitmap:wxBitmap(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmapbutton.html#wxbitmapbuttoncreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxBufferedDC.erl b/lib/wx/src/gen/wxBufferedDC.erl index 6e341a8552..9096f95612 100644 --- a/lib/wx/src/gen/wxBufferedDC.erl +++ b/lib/wx/src/gen/wxBufferedDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -74,7 +74,7 @@ new(Dc) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcwxbuffereddc">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% new(Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}) -> new(Dc,Area, []) </c></p> +%% new(Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}) -> new(Dc,Area, []) </c></p> %% <p><c> %% new(Dc::wxDC:wxDC(), [Option]) -> wxBufferedDC() </c> %%<br /> Option = {buffer, wxBitmap:wxBitmap()} | {style, integer()} @@ -93,7 +93,7 @@ new(#wx_ref{type=DcT,ref=DcRef}, Options) wxe_util:construct(?wxBufferedDC_new_2, <<DcRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}, [Option]) -> wxBufferedDC() +%% @spec (Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}, [Option]) -> wxBufferedDC() %% Option = {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcwxbuffereddc">external documentation</a>. new(#wx_ref{type=DcT,ref=DcRef},{AreaW,AreaH}, Options) @@ -115,7 +115,7 @@ init(This,Dc) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcinit">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}) -> init(This,Dc,Area, []) </c></p> +%% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}) -> init(This,Dc,Area, []) </c></p> %% <p><c> %% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), [Option]) -> ok </c> %%<br /> Option = {buffer, wxBitmap:wxBitmap()} | {style, integer()} @@ -135,7 +135,7 @@ init(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef}, Options) wxe_util:cast(?wxBufferedDC_Init_2, <<ThisRef:32/?UI,DcRef:32/?UI, BinOpt/binary>>). -%% @spec (This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}, [Option]) -> ok +%% @spec (This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}, [Option]) -> ok %% Option = {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcinit">external documentation</a>. init(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef},{AreaW,AreaH}, Options) diff --git a/lib/wx/src/gen/wxButton.erl b/lib/wx/src/gen/wxButton.erl index c0e21a5657..a75c45c5a3 100644 --- a/lib/wx/src/gen/wxButton.erl +++ b/lib/wx/src/gen/wxButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxButton() -%% Option = {label, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {label, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttonwxbutton">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -111,7 +111,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxButton(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {label, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {label, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttoncreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -127,7 +127,7 @@ create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, O wxe_util:call(?wxButton_Create, <<ThisRef:32/?UI,ParentRef:32/?UI,Id:32/?UI, 0:32,BinOpt/binary>>). -%% @spec () -> {W::integer(),H::integer()} +%% @spec () -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttongetdefaultsize">external documentation</a>. getDefaultSize() -> wxe_util:call(?wxButton_GetDefaultSize, diff --git a/lib/wx/src/gen/wxCalendarCtrl.erl b/lib/wx/src/gen/wxCalendarCtrl.erl index 8ad4d5954b..1bb4ecb1fa 100644 --- a/lib/wx/src/gen/wxCalendarCtrl.erl +++ b/lib/wx/src/gen/wxCalendarCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxCalendarCtrl() -%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlwxcalendarctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -114,7 +114,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxCalendarCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -297,7 +297,7 @@ resetAttr(#wx_ref{type=ThisT,ref=ThisRef},Day) wxe_util:cast(?wxCalendarCtrl_ResetAttr, <<ThisRef:32/?UI,Day:32/?UI>>). -%% @spec (This::wxCalendarCtrl(), Pos::{X::integer(),Y::integer()}) -> {WxCalendarHitTestResult,Date::wx:datetime(),Wd::WeekDay} +%% @spec (This::wxCalendarCtrl(), Pos::{X::integer(), Y::integer()}) -> {WxCalendarHitTestResult, Date::wx:datetime(), Wd::WeekDay} %% WxCalendarHitTestResult = integer() %% WeekDay = integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlhittest">external documentation</a>. diff --git a/lib/wx/src/gen/wxCaret.erl b/lib/wx/src/gen/wxCaret.erl index 3e1a3d544c..cbd868f388 100644 --- a/lib/wx/src/gen/wxCaret.erl +++ b/lib/wx/src/gen/wxCaret.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,7 +34,7 @@ %% @hidden parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (Window::wxWindow:wxWindow(), Size::{W::integer(),H::integer()}) -> wxCaret() +%% @spec (Window::wxWindow:wxWindow(), Size::{W::integer(), H::integer()}) -> wxCaret() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretwxcaret">external documentation</a>. new(#wx_ref{type=WindowT,ref=WindowRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -50,7 +50,7 @@ new(#wx_ref{type=WindowT,ref=WindowRef},Width,Height) wxe_util:construct(?wxCaret_new_3, <<WindowRef:32/?UI,Width:32/?UI,Height:32/?UI>>). -%% @spec (This::wxCaret(), Window::wxWindow:wxWindow(), Size::{W::integer(),H::integer()}) -> bool() +%% @spec (This::wxCaret(), Window::wxWindow:wxWindow(), Size::{W::integer(), H::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -74,14 +74,14 @@ getBlinkTime() -> wxe_util:call(?wxCaret_GetBlinkTime, <<>>). -%% @spec (This::wxCaret()) -> {X::integer(),Y::integer()} +%% @spec (This::wxCaret()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxCaret), wxe_util:call(?wxCaret_GetPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxCaret()) -> {W::integer(),H::integer()} +%% @spec (This::wxCaret()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxCaret), @@ -116,7 +116,7 @@ isVisible(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxCaret_IsVisible, <<ThisRef:32/?UI>>). -%% @spec (This::wxCaret(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxCaret(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretmove">external documentation</a>. move(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -139,7 +139,7 @@ setBlinkTime(Milliseconds) wxe_util:cast(?wxCaret_SetBlinkTime, <<Milliseconds:32/?UI>>). -%% @spec (This::wxCaret(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxCaret(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretsetsize">external documentation</a>. setSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxCheckBox.erl b/lib/wx/src/gen/wxCheckBox.erl index c484483379..19f01645c1 100644 --- a/lib/wx/src/gen/wxCheckBox.erl +++ b/lib/wx/src/gen/wxCheckBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -90,7 +90,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxCheckBox() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcheckbox.html#wxcheckboxwxcheckbox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> @@ -112,7 +112,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxCheckBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcheckbox.html#wxcheckboxcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> diff --git a/lib/wx/src/gen/wxCheckListBox.erl b/lib/wx/src/gen/wxCheckListBox.erl index c692997311..a1a07e1eec 100644 --- a/lib/wx/src/gen/wxCheckListBox.erl +++ b/lib/wx/src/gen/wxCheckListBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -96,7 +96,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxCheckListBox() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchecklistbox.html#wxchecklistboxwxchecklistbox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxChoice.erl b/lib/wx/src/gen/wxChoice.erl index eaf2f0352f..fa967d8487 100644 --- a/lib/wx/src/gen/wxChoice.erl +++ b/lib/wx/src/gen/wxChoice.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxChoice() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoice.html#wxchoicewxchoice">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -109,13 +109,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) wxe_util:construct(?wxChoice_new_3, <<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>). -%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool() +%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool() %% @equiv create(This,Parent,Id,Pos,Size,Choices, []) create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) -> create(This,Parent,Id,Pos,Size,Choices, []). -%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool() +%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool() %% Option = {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoice.html#wxchoicecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options) diff --git a/lib/wx/src/gen/wxChoicebook.erl b/lib/wx/src/gen/wxChoicebook.erl index b724d0cad2..f37457f0ed 100644 --- a/lib/wx/src/gen/wxChoicebook.erl +++ b/lib/wx/src/gen/wxChoicebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxChoicebook() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookwxchoicebook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -160,7 +160,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxChoicebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxChoicebook_GetSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxChoicebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxChoicebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi wxe_util:cast(?wxChoicebook_SetImageList, <<ThisRef:32/?UI,ImageListRef:32/?UI>>). -%% @spec (This::wxChoicebook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxChoicebook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebooksetpagesize">external documentation</a>. setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxColourPickerCtrl.erl b/lib/wx/src/gen/wxColourPickerCtrl.erl index 4f0816e1fd..60776925b9 100644 --- a/lib/wx/src/gen/wxColourPickerCtrl.erl +++ b/lib/wx/src/gen/wxColourPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxColourPickerCtrl() -%% Option = {col, wx:colour()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {col, wx:colour()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcolourpickerctrl.html#wxcolourpickerctrlwxcolourpickerctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -116,7 +116,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxColourPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {col, wx:colour()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {col, wx:colour()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcolourpickerctrl.html#wxcolourpickerctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxComboBox.erl b/lib/wx/src/gen/wxComboBox.erl index 061e886734..f743df4e93 100644 --- a/lib/wx/src/gen/wxComboBox.erl +++ b/lib/wx/src/gen/wxComboBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -96,7 +96,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxComboBox() -%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} +%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcombobox.html#wxcomboboxwxcombobox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -112,13 +112,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) wxe_util:construct(?wxComboBox_new_3, <<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>). -%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool() +%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool() %% @equiv create(This,Parent,Id,Value,Pos,Size,Choices, []) create(This,Parent,Id,Value,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) -> create(This,Parent,Id,Value,Pos,Size,Choices, []). -%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool() +%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool() %% Option = {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcombobox.html#wxcomboboxcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,{PosX,PosY},{SizeW,SizeH},Choices, Options) diff --git a/lib/wx/src/gen/wxContextMenuEvent.erl b/lib/wx/src/gen/wxContextMenuEvent.erl index 56ed82f37c..0050b97b89 100644 --- a/lib/wx/src/gen/wxContextMenuEvent.erl +++ b/lib/wx/src/gen/wxContextMenuEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,14 +45,14 @@ parent_class(wxCommandEvent) -> true; parent_class(wxEvent) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxContextMenuEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxContextMenuEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcontextmenuevent.html#wxcontextmenueventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxContextMenuEvent), wxe_util:call(?wxContextMenuEvent_GetPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxContextMenuEvent(), Pos::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxContextMenuEvent(), Pos::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcontextmenuevent.html#wxcontextmenueventsetposition">external documentation</a>. setPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) when is_integer(PosX),is_integer(PosY) -> diff --git a/lib/wx/src/gen/wxDC.erl b/lib/wx/src/gen/wxDC.erl index 9bce1249f8..ba498c651a 100644 --- a/lib/wx/src/gen/wxDC.erl +++ b/lib/wx/src/gen/wxDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -52,14 +52,14 @@ %% @hidden parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxDC(), DestPt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Source::wxDC(), SrcPt::{X::integer(),Y::integer()}) -> bool() +%% @spec (This::wxDC(), DestPt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Source::wxDC(), SrcPt::{X::integer(), Y::integer()}) -> bool() %% @equiv blit(This,DestPt,Sz,Source,SrcPt, []) blit(This,DestPt={DestPtX,DestPtY},Sz={SzW,SzH},Source,SrcPt={SrcPtX,SrcPtY}) when is_record(This, wx_ref),is_integer(DestPtX),is_integer(DestPtY),is_integer(SzW),is_integer(SzH),is_record(Source, wx_ref),is_integer(SrcPtX),is_integer(SrcPtY) -> blit(This,DestPt,Sz,Source,SrcPt, []). -%% @spec (This::wxDC(), DestPt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Source::wxDC(), SrcPt::{X::integer(),Y::integer()}, [Option]) -> bool() -%% Option = {rop, integer()} | {useMask, bool()} | {srcPtMask, {X::integer(),Y::integer()}} +%% @spec (This::wxDC(), DestPt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Source::wxDC(), SrcPt::{X::integer(), Y::integer()}, [Option]) -> bool() +%% Option = {rop, integer()} | {useMask, bool()} | {srcPtMask, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcblit">external documentation</a>. blit(#wx_ref{type=ThisT,ref=ThisRef},{DestPtX,DestPtY},{SzW,SzH},#wx_ref{type=SourceT,ref=SourceRef},{SrcPtX,SrcPtY}, Options) when is_integer(DestPtX),is_integer(DestPtY),is_integer(SzW),is_integer(SzH),is_integer(SrcPtX),is_integer(SrcPtY),is_list(Options) -> @@ -95,7 +95,7 @@ computeScaleAndOrigin(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxDC_ComputeScaleAndOrigin, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdccrosshair">external documentation</a>. crossHair(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -142,7 +142,7 @@ deviceToLogicalYRel(#wx_ref{type=ThisT,ref=ThisRef},Y) wxe_util:call(?wxDC_DeviceToLogicalYRel, <<ThisRef:32/?UI,Y:32/?UI>>). -%% @spec (This::wxDC(), Pt1::{X::integer(),Y::integer()}, Pt2::{X::integer(),Y::integer()}, Centre::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Pt1::{X::integer(), Y::integer()}, Pt2::{X::integer(), Y::integer()}, Centre::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawarc">external documentation</a>. drawArc(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y},{CentreX,CentreY}) when is_integer(Pt1X),is_integer(Pt1Y),is_integer(Pt2X),is_integer(Pt2Y),is_integer(CentreX),is_integer(CentreY) -> @@ -150,13 +150,13 @@ drawArc(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y},{CentreX,CentreY wxe_util:cast(?wxDC_DrawArc, <<ThisRef:32/?UI,Pt1X:32/?UI,Pt1Y:32/?UI,Pt2X:32/?UI,Pt2Y:32/?UI,CentreX:32/?UI,CentreY:32/?UI>>). -%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(), Y::integer()}) -> ok %% @equiv drawBitmap(This,Bmp,Pt, []) drawBitmap(This,Bmp,Pt={PtX,PtY}) when is_record(This, wx_ref),is_record(Bmp, wx_ref),is_integer(PtX),is_integer(PtY) -> drawBitmap(This,Bmp,Pt, []). -%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(),Y::integer()}, [Option]) -> ok +%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(), Y::integer()}, [Option]) -> ok %% Option = {useMask, bool()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawbitmap">external documentation</a>. drawBitmap(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BmpT,ref=BmpRef},{PtX,PtY}, Options) @@ -169,7 +169,7 @@ drawBitmap(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BmpT,ref=BmpRef},{PtX,Pt wxe_util:cast(?wxDC_DrawBitmap, <<ThisRef:32/?UI,BmpRef:32/?UI,PtX:32/?UI,PtY:32/?UI, BinOpt/binary>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawcheckmark">external documentation</a>. drawCheckMark(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -177,7 +177,7 @@ drawCheckMark(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) wxe_util:cast(?wxDC_DrawCheckMark, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Radius::integer()) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Radius::integer()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawcircle">external documentation</a>. drawCircle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Radius) when is_integer(PtX),is_integer(PtY),is_integer(Radius) -> @@ -185,7 +185,7 @@ drawCircle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Radius) wxe_util:cast(?wxDC_DrawCircle, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,Radius:32/?UI>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipse">external documentation</a>. drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -193,7 +193,7 @@ drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) wxe_util:cast(?wxDC_DrawEllipse_1, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipse">external documentation</a>. drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH}) when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) -> @@ -201,7 +201,7 @@ drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH}) wxe_util:cast(?wxDC_DrawEllipse_2, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Sa::float(), Ea::float()) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Sa::float(), Ea::float()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipticarc">external documentation</a>. drawEllipticArc(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Sa,Ea) when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH),is_float(Sa),is_float(Ea) -> @@ -209,7 +209,7 @@ drawEllipticArc(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Sa,Ea) wxe_util:cast(?wxDC_DrawEllipticArc, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI,0:32,Sa:64/?F,Ea:64/?F>>). -%% @spec (This::wxDC(), Icon::wxIcon:wxIcon(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Icon::wxIcon:wxIcon(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawicon">external documentation</a>. drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -218,13 +218,13 @@ drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},{PtX,Pt wxe_util:cast(?wxDC_DrawIcon, <<ThisRef:32/?UI,IconRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @equiv drawLabel(This,Text,Rect, []) drawLabel(This,Text,Rect={RectX,RectY,RectW,RectH}) when is_record(This, wx_ref),is_list(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> drawLabel(This,Text,Rect, []). -%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok +%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok %% Option = {alignment, integer()} | {indexAccel, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawlabel">external documentation</a>. drawLabel(#wx_ref{type=ThisT,ref=ThisRef},Text,{RectX,RectY,RectW,RectH}, Options) @@ -238,7 +238,7 @@ drawLabel(#wx_ref{type=ThisT,ref=ThisRef},Text,{RectX,RectY,RectW,RectH}, Option wxe_util:cast(?wxDC_DrawLabel, <<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI, BinOpt/binary>>). -%% @spec (This::wxDC(), Pt1::{X::integer(),Y::integer()}, Pt2::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Pt1::{X::integer(), Y::integer()}, Pt2::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawline">external documentation</a>. drawLine(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y}) when is_integer(Pt1X),is_integer(Pt1Y),is_integer(Pt2X),is_integer(Pt2Y) -> @@ -246,13 +246,13 @@ drawLine(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y}) wxe_util:cast(?wxDC_DrawLine, <<ThisRef:32/?UI,Pt1X:32/?UI,Pt1Y:32/?UI,Pt2X:32/?UI,Pt2Y:32/?UI>>). -%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}]) -> ok +%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}]) -> ok %% @equiv drawLines(This,Points, []) drawLines(This,Points) when is_record(This, wx_ref),is_list(Points) -> drawLines(This,Points, []). -%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}], [Option]) -> ok +%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}], [Option]) -> ok %% Option = {xoffset, integer()} | {yoffset, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawlines">external documentation</a>. drawLines(#wx_ref{type=ThisT,ref=ThisRef},Points, Options) @@ -266,13 +266,13 @@ drawLines(#wx_ref{type=ThisT,ref=ThisRef},Points, Options) <<ThisRef:32/?UI,(length(Points)):32/?UI, (<< <<X:32/?I,Y:32/?I>> || {X,Y} <- Points>>)/binary, BinOpt/binary>>). -%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}]) -> ok +%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}]) -> ok %% @equiv drawPolygon(This,Points, []) drawPolygon(This,Points) when is_record(This, wx_ref),is_list(Points) -> drawPolygon(This,Points, []). -%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}], [Option]) -> ok +%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}], [Option]) -> ok %% Option = {xoffset, integer()} | {yoffset, integer()} | {fillStyle, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawpolygon">external documentation</a>. drawPolygon(#wx_ref{type=ThisT,ref=ThisRef},Points, Options) @@ -287,7 +287,7 @@ drawPolygon(#wx_ref{type=ThisT,ref=ThisRef},Points, Options) <<ThisRef:32/?UI,(length(Points)):32/?UI, (<< <<X:32/?I,Y:32/?I>> || {X,Y} <- Points>>)/binary, BinOpt/binary>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawpoint">external documentation</a>. drawPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -295,7 +295,7 @@ drawPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:cast(?wxDC_DrawPoint, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrectangle">external documentation</a>. drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -303,7 +303,7 @@ drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) wxe_util:cast(?wxDC_DrawRectangle_1, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrectangle">external documentation</a>. drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH}) when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) -> @@ -311,7 +311,7 @@ drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH}) wxe_util:cast(?wxDC_DrawRectangle_2, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI>>). -%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(),Y::integer()}, Angle::float()) -> ok +%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(), Y::integer()}, Angle::float()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrotatedtext">external documentation</a>. drawRotatedText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY},Angle) when is_list(Text),is_integer(PtX),is_integer(PtY),is_float(Angle) -> @@ -320,7 +320,7 @@ drawRotatedText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY},Angle) wxe_util:cast(?wxDC_DrawRotatedText, <<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,PtX:32/?UI,PtY:32/?UI,Angle:64/?F>>). -%% @spec (This::wxDC(), R::{X::integer(),Y::integer(),W::integer(),H::integer()}, Radius::float()) -> ok +%% @spec (This::wxDC(), R::{X::integer(), Y::integer(), W::integer(), H::integer()}, Radius::float()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawroundedrectangle">external documentation</a>. drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RX,RY,RW,RH},Radius) when is_integer(RX),is_integer(RY),is_integer(RW),is_integer(RH),is_float(Radius) -> @@ -328,7 +328,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RX,RY,RW,RH},Radius) wxe_util:cast(?wxDC_DrawRoundedRectangle_2, <<ThisRef:32/?UI,RX:32/?UI,RY:32/?UI,RW:32/?UI,RH:32/?UI,0:32,Radius:64/?F>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Radius::float()) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Radius::float()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawroundedrectangle">external documentation</a>. drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Radius) when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH),is_float(Radius) -> @@ -336,7 +336,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Radius) wxe_util:cast(?wxDC_DrawRoundedRectangle_3, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI,0:32,Radius:64/?F>>). -%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawtext">external documentation</a>. drawText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY}) when is_list(Text),is_integer(PtX),is_integer(PtY) -> @@ -359,13 +359,13 @@ endPage(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxDC_EndPage, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour()) -> bool() +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour()) -> bool() %% @equiv floodFill(This,Pt,Col, []) floodFill(This,Pt={PtX,PtY},Col) when is_record(This, wx_ref),is_integer(PtX),is_integer(PtY),tuple_size(Col) =:= 3; tuple_size(Col) =:= 4 -> floodFill(This,Pt,Col, []). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour(), [Option]) -> bool() +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour(), [Option]) -> bool() %% Option = {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcfloodfill">external documentation</a>. floodFill(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col, Options) @@ -412,7 +412,7 @@ getCharWidth(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxDC_GetCharWidth, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetclippingbox">external documentation</a>. getClippingBox(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -450,7 +450,7 @@ getMapMode(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxDC_GetMapMode, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), String::string()) -> {W::integer(),H::integer()} +%% @spec (This::wxDC(), String::string()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetmultilinetextextent">external documentation</a>. getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String) when is_list(String) -> @@ -459,7 +459,7 @@ getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String) wxe_util:call(?wxDC_GetMultiLineTextExtent_1, <<ThisRef:32/?UI,(byte_size(String_UC)):32/?UI,(String_UC)/binary, 0:(((8- ((0+byte_size(String_UC)) band 16#7)) band 16#7))/unit:8>>). -%% @spec (This::wxDC(), String::string(), [Option]) -> {Width::integer(),Height::integer(),HeightLine::integer()} +%% @spec (This::wxDC(), String::string(), [Option]) -> {Width::integer(), Height::integer(), HeightLine::integer()} %% Option = {font, wxFont:wxFont()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetmultilinetextextent">external documentation</a>. getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options) @@ -489,7 +489,7 @@ getPen(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxDC_GetPen, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour()) -> bool() +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour()) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetpixel">external documentation</a>. getPixel(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col) when is_integer(PtX),is_integer(PtY),tuple_size(Col) =:= 3; tuple_size(Col) =:= 4 -> @@ -497,21 +497,21 @@ getPixel(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col) wxe_util:call(?wxDC_GetPixel, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,(wxe_util:colour_bin(Col)):16/binary>>). -%% @spec (This::wxDC()) -> {W::integer(),H::integer()} +%% @spec (This::wxDC()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetppi">external documentation</a>. getPPI(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxDC), wxe_util:call(?wxDC_GetPPI, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC()) -> {W::integer(),H::integer()} +%% @spec (This::wxDC()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxDC), wxe_util:call(?wxDC_GetSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC()) -> {W::integer(),H::integer()} +%% @spec (This::wxDC()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetsizemm">external documentation</a>. getSizeMM(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxDC), @@ -525,7 +525,7 @@ getTextBackground(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxDC_GetTextBackground, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), String::string()) -> {W::integer(),H::integer()} +%% @spec (This::wxDC(), String::string()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgettextextent">external documentation</a>. getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String) when is_list(String) -> @@ -534,7 +534,7 @@ getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String) wxe_util:call(?wxDC_GetTextExtent_1, <<ThisRef:32/?UI,(byte_size(String_UC)):32/?UI,(String_UC)/binary, 0:(((8- ((0+byte_size(String_UC)) band 16#7)) band 16#7))/unit:8>>). -%% @spec (This::wxDC(), String::string(), [Option]) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()} +%% @spec (This::wxDC(), String::string(), [Option]) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()} %% Option = {theFont, wxFont:wxFont()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgettextextent">external documentation</a>. getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options) @@ -554,14 +554,14 @@ getTextForeground(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxDC_GetTextForeground, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC()) -> {X::float(),Y::float()} +%% @spec (This::wxDC()) -> {X::float(), Y::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetuserscale">external documentation</a>. getUserScale(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxDC), wxe_util:call(?wxDC_GetUserScale, <<ThisRef:32/?UI>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfillconcentric">external documentation</a>. gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},InitialColour,DestColour) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4 -> @@ -569,7 +569,7 @@ gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH} wxe_util:cast(?wxDC_GradientFillConcentric_3, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,(wxe_util:colour_bin(InitialColour)):16/binary,(wxe_util:colour_bin(DestColour)):16/binary>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), CircleCenter::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), CircleCenter::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfillconcentric">external documentation</a>. gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},InitialColour,DestColour,{CircleCenterX,CircleCenterY}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4,is_integer(CircleCenterX),is_integer(CircleCenterY) -> @@ -577,13 +577,13 @@ gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH} wxe_util:cast(?wxDC_GradientFillConcentric_4, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,(wxe_util:colour_bin(InitialColour)):16/binary,(wxe_util:colour_bin(DestColour)):16/binary,CircleCenterX:32/?UI,CircleCenterY:32/?UI>>). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok %% @equiv gradientFillLinear(This,Rect,InitialColour,DestColour, []) gradientFillLinear(This,Rect={RectX,RectY,RectW,RectH},InitialColour,DestColour) when is_record(This, wx_ref),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4 -> gradientFillLinear(This,Rect,InitialColour,DestColour, []). -%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), [Option]) -> ok +%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), [Option]) -> ok %% Option = {nDirection, WxDirection} %% WxDirection = integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfilllinear">external documentation</a>. @@ -710,7 +710,7 @@ setBrush(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BrushT,ref=BrushRef}) -> %% setClippingRegion(This::wxDC(), Region::wxRegion:wxRegion()) -> ok </c> %% </p> %% <p><c> -%% setClippingRegion(This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok </c> +%% setClippingRegion(This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok </c> %% </p> setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) -> ?CLASS(ThisT,wxDC), @@ -723,7 +723,7 @@ setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) wxe_util:cast(?wxDC_SetClippingRegion_1_1, <<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>). -%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcsetclippingregion">external documentation</a>. setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH}) when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) -> diff --git a/lib/wx/src/gen/wxDatePickerCtrl.erl b/lib/wx/src/gen/wxDatePickerCtrl.erl index 2de51ce71d..8a1700e9cd 100644 --- a/lib/wx/src/gen/wxDatePickerCtrl.erl +++ b/lib/wx/src/gen/wxDatePickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxDatePickerCtrl() -%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdatepickerctrl.html#wxdatepickerctrlwxdatepickerctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxDialog.erl b/lib/wx/src/gen/wxDialog.erl index 8c0bd2cd76..514a62813e 100644 --- a/lib/wx/src/gen/wxDialog.erl +++ b/lib/wx/src/gen/wxDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ new(Parent,Id,Title) new(Parent,Id,Title, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxDialog() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdialog.html#wxdialogwxdialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -116,7 +116,7 @@ create(This,Parent,Id,Title) create(This,Parent,Id,Title, []). %% @spec (This::wxDialog(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdialog.html#wxdialogcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> diff --git a/lib/wx/src/gen/wxDirDialog.erl b/lib/wx/src/gen/wxDirDialog.erl index 7849dce0a7..28db3daf1d 100644 --- a/lib/wx/src/gen/wxDirDialog.erl +++ b/lib/wx/src/gen/wxDirDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxDirDialog() -%% Option = {title, string()} | {defaultPath, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} | {sz, {W::integer(),H::integer()}} +%% Option = {title, string()} | {defaultPath, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} | {sz, {W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirdialog.html#wxdirdialogwxdirdialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxDirPickerCtrl.erl b/lib/wx/src/gen/wxDirPickerCtrl.erl index 7fb70b71e3..2b24bc4bb0 100644 --- a/lib/wx/src/gen/wxDirPickerCtrl.erl +++ b/lib/wx/src/gen/wxDirPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxDirPickerCtrl() -%% Option = {path, string()} | {message, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {path, string()} | {message, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirpickerctrl.html#wxdirpickerctrlwxdirpickerctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -117,7 +117,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxDirPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {path, string()} | {message, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {path, string()} | {message, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirpickerctrl.html#wxdirpickerctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxFileDialog.erl b/lib/wx/src/gen/wxFileDialog.erl index cba9705335..c6779927e9 100644 --- a/lib/wx/src/gen/wxFileDialog.erl +++ b/lib/wx/src/gen/wxFileDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxFileDialog() -%% Option = {message, string()} | {defaultDir, string()} | {defaultFile, string()} | {wildCard, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} | {sz, {W::integer(),H::integer()}} +%% Option = {message, string()} | {defaultDir, string()} | {defaultFile, string()} | {wildCard, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} | {sz, {W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfiledialog.html#wxfiledialogwxfiledialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxFilePickerCtrl.erl b/lib/wx/src/gen/wxFilePickerCtrl.erl index a3034aaa86..93bfa72380 100644 --- a/lib/wx/src/gen/wxFilePickerCtrl.erl +++ b/lib/wx/src/gen/wxFilePickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxFilePickerCtrl() -%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfilepickerctrl.html#wxfilepickerctrlwxfilepickerctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -118,7 +118,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxFilePickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfilepickerctrl.html#wxfilepickerctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxFontPickerCtrl.erl b/lib/wx/src/gen/wxFontPickerCtrl.erl index 93d63cc930..3050011b60 100644 --- a/lib/wx/src/gen/wxFontPickerCtrl.erl +++ b/lib/wx/src/gen/wxFontPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxFontPickerCtrl() -%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfontpickerctrl.html#wxfontpickerctrlwxfontpickerctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -117,7 +117,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxFontPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfontpickerctrl.html#wxfontpickerctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxFrame.erl b/lib/wx/src/gen/wxFrame.erl index 5cd1e3dfd3..7e25bc8762 100644 --- a/lib/wx/src/gen/wxFrame.erl +++ b/lib/wx/src/gen/wxFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -97,7 +97,7 @@ new(Parent,Id,Title) new(Parent,Id,Title, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxFrame() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframewxframe">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -118,7 +118,7 @@ create(This,Parent,Id,Title) create(This,Parent,Id,Title, []). %% @spec (This::wxFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -172,7 +172,7 @@ createToolBar(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxFrame_CreateToolBar, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxFrame()) -> {X::integer(),Y::integer()} +%% @spec (This::wxFrame()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframegetclientareaorigin">external documentation</a>. getClientAreaOrigin(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxFrame), diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl index 032d42535d..a30d8cefd9 100644 --- a/lib/wx/src/gen/wxGLCanvas.erl +++ b/lib/wx/src/gen/wxGLCanvas.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -86,7 +86,7 @@ new(Parent) %% new(Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas()) -> new(Parent,Shared, []) </c></p> %% <p><c> %% new(Parent::wxWindow:wxWindow(), [Option]) -> wxGLCanvas() </c> -%%<br /> Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()} +%%<br /> Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()} %% </p> new(Parent,Shared) @@ -109,7 +109,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options) <<ParentRef:32/?UI, 0:32,BinOpt/binary>>). %% @spec (Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas(), [Option]) -> wxGLCanvas() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxglcanvas.html#wxglcanvaswxglcanvas">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=SharedT,ref=SharedRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxGauge.erl b/lib/wx/src/gen/wxGauge.erl index 5028b29bba..484fd36936 100644 --- a/lib/wx/src/gen/wxGauge.erl +++ b/lib/wx/src/gen/wxGauge.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -90,7 +90,7 @@ new(Parent,Id,Range) new(Parent,Id,Range, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Range::integer(), [Option]) -> wxGauge() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgauge.html#wxgaugewxgauge">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options) when is_integer(Id),is_integer(Range),is_list(Options) -> @@ -111,7 +111,7 @@ create(This,Parent,Id,Range) create(This,Parent,Id,Range, []). %% @spec (This::wxGauge(), Parent::wxWindow:wxWindow(), Id::integer(), Range::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgauge.html#wxgaugecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options) when is_integer(Id),is_integer(Range),is_list(Options) -> diff --git a/lib/wx/src/gen/wxGenericDirCtrl.erl b/lib/wx/src/gen/wxGenericDirCtrl.erl index 97944710f0..626a454d2a 100644 --- a/lib/wx/src/gen/wxGenericDirCtrl.erl +++ b/lib/wx/src/gen/wxGenericDirCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxGenericDirCtrl() -%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()} +%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgenericdirctrl.html#wxgenericdirctrlwxgenericdirctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -115,7 +115,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxGenericDirCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()} +%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgenericdirctrl.html#wxgenericdirctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxGraphicsContext.erl b/lib/wx/src/gen/wxGraphicsContext.erl index 040867cb11..05c56dd4b2 100644 --- a/lib/wx/src/gen/wxGraphicsContext.erl +++ b/lib/wx/src/gen/wxGraphicsContext.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -192,13 +192,13 @@ drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},X,Y,W,H wxe_util:cast(?wxGraphicsContext_DrawIcon, <<ThisRef:32/?UI,IconRef:32/?UI,X:64/?F,Y:64/?F,W:64/?F,H:64/?F>>). -%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}) -> ok %% @equiv drawLines(This,N,Points, []) drawLines(This,N,Points={PointsX,PointsY}) when is_record(This, wx_ref),is_integer(N),is_number(PointsX),is_number(PointsY) -> drawLines(This,N,Points, []). -%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}, [Option]) -> ok +%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}, [Option]) -> ok %% Option = {fillStyle, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextdrawlines">external documentation</a>. drawLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY}, Options) @@ -331,7 +331,7 @@ getPartialTextExtents(#wx_ref{type=ThisT,ref=ThisRef},Text,Widths) <<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,(length(Widths)):32/?UI, 0:32, (<< <<C:64/float>> || C <- Widths>>)/binary>>). -%% @spec (This::wxGraphicsContext(), Text::string()) -> {Width::float(),Height::float(),Descent::float(),ExternalLeading::float()} +%% @spec (This::wxGraphicsContext(), Text::string()) -> {Width::float(), Height::float(), Descent::float(), ExternalLeading::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextgettextextent">external documentation</a>. getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},Text) when is_list(Text) -> @@ -438,7 +438,7 @@ strokeLine(#wx_ref{type=ThisT,ref=ThisRef},X1,Y1,X2,Y2) wxe_util:cast(?wxGraphicsContext_StrokeLine, <<ThisRef:32/?UI,0:32,X1:64/?F,Y1:64/?F,X2:64/?F,Y2:64/?F>>). -%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextstrokelines">external documentation</a>. strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY}) when is_integer(N),is_number(PointsX),is_number(PointsY) -> @@ -446,7 +446,7 @@ strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY}) wxe_util:cast(?wxGraphicsContext_StrokeLines_2, <<ThisRef:32/?UI,N:32/?UI,PointsX:64/float,PointsY:64/float>>). -%% @spec (This::wxGraphicsContext(), N::integer(), BeginPoints::{X::float(),Y::float()}, EndPoints::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsContext(), N::integer(), BeginPoints::{X::float(), Y::float()}, EndPoints::{X::float(), Y::float()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextstrokelines">external documentation</a>. strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{BeginPointsX,BeginPointsY},{EndPointsX,EndPointsY}) when is_integer(N),is_number(BeginPointsX),is_number(BeginPointsY),is_number(EndPointsX),is_number(EndPointsY) -> diff --git a/lib/wx/src/gen/wxGraphicsMatrix.erl b/lib/wx/src/gen/wxGraphicsMatrix.erl index 38ea007c58..635a2027b3 100644 --- a/lib/wx/src/gen/wxGraphicsMatrix.erl +++ b/lib/wx/src/gen/wxGraphicsMatrix.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ concat(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=TT,ref=TRef}) -> wxe_util:cast(?wxGraphicsMatrix_Concat, <<ThisRef:32/?UI,TRef:32/?UI>>). -%% @spec (This::wxGraphicsMatrix()) -> {A::float(),B::float(),C::float(),D::float(),Tx::float(),Ty::float()} +%% @spec (This::wxGraphicsMatrix()) -> {A::float(), B::float(), C::float(), D::float(), Tx::float(), Ty::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixget">external documentation</a>. get(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGraphicsMatrix), @@ -128,14 +128,14 @@ set(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:cast(?wxGraphicsMatrix_Set, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxGraphicsMatrix()) -> {X::float(),Y::float()} +%% @spec (This::wxGraphicsMatrix()) -> {X::float(), Y::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixtransformpoint">external documentation</a>. transformPoint(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGraphicsMatrix), wxe_util:call(?wxGraphicsMatrix_TransformPoint, <<ThisRef:32/?UI>>). -%% @spec (This::wxGraphicsMatrix()) -> {Dx::float(),Dy::float()} +%% @spec (This::wxGraphicsMatrix()) -> {Dx::float(), Dy::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixtransformdistance">external documentation</a>. transformDistance(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGraphicsMatrix), diff --git a/lib/wx/src/gen/wxGraphicsPath.erl b/lib/wx/src/gen/wxGraphicsPath.erl index ff2dfb07a4..e41496c641 100644 --- a/lib/wx/src/gen/wxGraphicsPath.erl +++ b/lib/wx/src/gen/wxGraphicsPath.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -40,7 +40,7 @@ parent_class(wxGraphicsObject) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxGraphicsPath(), P::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsPath(), P::{X::float(), Y::float()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathmovetopoint">external documentation</a>. moveToPoint(#wx_ref{type=ThisT,ref=ThisRef},{PX,PY}) when is_number(PX),is_number(PY) -> @@ -56,7 +56,7 @@ moveToPoint(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:cast(?wxGraphicsPath_MoveToPoint_2, <<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F>>). -%% @spec (This::wxGraphicsPath(), C::{X::float(),Y::float()}, R::float(), StartAngle::float(), EndAngle::float(), Clockwise::bool()) -> ok +%% @spec (This::wxGraphicsPath(), C::{X::float(), Y::float()}, R::float(), StartAngle::float(), EndAngle::float(), Clockwise::bool()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddarc">external documentation</a>. addArc(#wx_ref{type=ThisT,ref=ThisRef},{CX,CY},R,StartAngle,EndAngle,Clockwise) when is_number(CX),is_number(CY),is_float(R),is_float(StartAngle),is_float(EndAngle),is_boolean(Clockwise) -> @@ -88,7 +88,7 @@ addCircle(#wx_ref{type=ThisT,ref=ThisRef},X,Y,R) wxe_util:cast(?wxGraphicsPath_AddCircle, <<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F,R:64/?F>>). -%% @spec (This::wxGraphicsPath(), C1::{X::float(),Y::float()}, C2::{X::float(),Y::float()}, E::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsPath(), C1::{X::float(), Y::float()}, C2::{X::float(), Y::float()}, E::{X::float(), Y::float()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddcurvetopoint">external documentation</a>. addCurveToPoint(#wx_ref{type=ThisT,ref=ThisRef},{C1X,C1Y},{C2X,C2Y},{EX,EY}) when is_number(C1X),is_number(C1Y),is_number(C2X),is_number(C2Y),is_number(EX),is_number(EY) -> @@ -112,7 +112,7 @@ addEllipse(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H) wxe_util:cast(?wxGraphicsPath_AddEllipse, <<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F,W:64/?F,H:64/?F>>). -%% @spec (This::wxGraphicsPath(), P::{X::float(),Y::float()}) -> ok +%% @spec (This::wxGraphicsPath(), P::{X::float(), Y::float()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddlinetopoint">external documentation</a>. addLineToPoint(#wx_ref{type=ThisT,ref=ThisRef},{PX,PY}) when is_number(PX),is_number(PY) -> @@ -167,7 +167,7 @@ closeSubpath(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxGraphicsPath_CloseSubpath, <<ThisRef:32/?UI>>). -%% @spec (This::wxGraphicsPath(), C::{X::float(),Y::float()}) -> bool() +%% @spec (This::wxGraphicsPath(), C::{X::float(), Y::float()}) -> bool() %% @equiv contains(This,C, []) contains(This,C={CX,CY}) when is_record(This, wx_ref),is_number(CX),is_number(CY) -> @@ -179,7 +179,7 @@ contains(This,C={CX,CY}) %% <p><c> %% contains(This::wxGraphicsPath(), X::float(), Y::float()) -> contains(This,X,Y, []) </c></p> %% <p><c> -%% contains(This::wxGraphicsPath(), C::{X::float(),Y::float()}, [Option]) -> bool() </c> +%% contains(This::wxGraphicsPath(), C::{X::float(), Y::float()}, [Option]) -> bool() </c> %%<br /> Option = {fillStyle, integer()} %% </p> @@ -207,14 +207,14 @@ contains(#wx_ref{type=ThisT,ref=ThisRef},X,Y, Options) wxe_util:call(?wxGraphicsPath_Contains_3, <<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F, BinOpt/binary>>). -%% @spec (This::wxGraphicsPath()) -> {X::float(),Y::float(),W::float(),H::float()} +%% @spec (This::wxGraphicsPath()) -> {X::float(), Y::float(), W::float(), H::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathgetbox">external documentation</a>. getBox(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGraphicsPath), wxe_util:call(?wxGraphicsPath_GetBox, <<ThisRef:32/?UI>>). -%% @spec (This::wxGraphicsPath()) -> {X::float(),Y::float()} +%% @spec (This::wxGraphicsPath()) -> {X::float(), Y::float()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathgetcurrentpoint">external documentation</a>. getCurrentPoint(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGraphicsPath), diff --git a/lib/wx/src/gen/wxGrid.erl b/lib/wx/src/gen/wxGrid.erl index 7b62ec33a4..531fed05c1 100644 --- a/lib/wx/src/gen/wxGrid.erl +++ b/lib/wx/src/gen/wxGrid.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -151,7 +151,7 @@ new(Parent,Id) %% new(Parent::wxWindow:wxWindow(), X::integer(), Y::integer()) -> new(Parent,X,Y, []) </c></p> %% <p><c> %% new(Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxGrid() </c> -%%<br /> Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%%<br /> Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% </p> new(Parent,X,Y) @@ -306,7 +306,7 @@ beginBatch(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxGrid_BeginBatch, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridblocktodevicerect">external documentation</a>. blockToDeviceRect(#wx_ref{type=ThisT,ref=ThisRef},{TopLeftR,TopLeftC},{BottomRightR,BottomRightC}) when is_integer(TopLeftR),is_integer(TopLeftC),is_integer(BottomRightR),is_integer(BottomRightC) -> @@ -342,7 +342,7 @@ canEnableCellControl(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_CanEnableCellControl, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridcelltorect">external documentation</a>. cellToRect(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC}) when is_integer(CoordsR),is_integer(CoordsC) -> @@ -350,7 +350,7 @@ cellToRect(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC}) wxe_util:call(?wxGrid_CellToRect_1, <<ThisRef:32/?UI,CoordsR:32/?UI,CoordsC:32/?UI>>). -%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridcelltorect">external documentation</a>. cellToRect(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) when is_integer(Row),is_integer(Col) -> @@ -586,7 +586,7 @@ getBatchCount(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetBatchCount, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {Horiz::integer(),Vert::integer()} +%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {Horiz::integer(), Vert::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcellalignment">external documentation</a>. getCellAlignment(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) when is_integer(Row),is_integer(Col) -> @@ -634,7 +634,7 @@ getCellTextColour(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) wxe_util:call(?wxGrid_GetCellTextColour, <<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> string() +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> string() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcellvalue">external documentation</a>. getCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC}) when is_integer(CoordsR),is_integer(CoordsC) -> @@ -650,7 +650,7 @@ getCellValue(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) wxe_util:call(?wxGrid_GetCellValue_2, <<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>). -%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()} +%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcollabelalignment">external documentation</a>. getColLabelAlignment(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), @@ -679,7 +679,7 @@ getColMinimalAcceptableWidth(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetColMinimalAcceptableWidth, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()} +%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetdefaultcellalignment">external documentation</a>. getDefaultCellAlignment(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), @@ -728,7 +728,7 @@ getDefaultEditor(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetDefaultEditor, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), C::{R::integer(),C::integer()}) -> wxGridCellEditor:wxGridCellEditor() +%% @spec (This::wxGrid(), C::{R::integer(), C::integer()}) -> wxGridCellEditor:wxGridCellEditor() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetdefaulteditorforcell">external documentation</a>. getDefaultEditorForCell(#wx_ref{type=ThisT,ref=ThisRef},{CR,CC}) when is_integer(CR),is_integer(CC) -> @@ -869,7 +869,7 @@ getRowMinimalAcceptableHeight(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetRowMinimalAcceptableHeight, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()} +%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetrowlabelalignment">external documentation</a>. getRowLabelAlignment(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), @@ -913,7 +913,7 @@ getScrollLineY(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetScrollLineY, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}] +%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}] %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectedcells">external documentation</a>. getSelectedCells(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), @@ -941,14 +941,14 @@ getSelectionBackground(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_GetSelectionBackground, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}] +%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}] %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectionblocktopleft">external documentation</a>. getSelectionBlockTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), wxe_util:call(?wxGrid_GetSelectionBlockTopLeft, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}] +%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}] %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectionblockbottomright">external documentation</a>. getSelectionBlockBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGrid), @@ -1065,7 +1065,7 @@ isEditable(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_IsEditable, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> bool() +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridisinselection">external documentation</a>. isInSelection(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC}) when is_integer(CoordsR),is_integer(CoordsC) -> @@ -1096,7 +1096,7 @@ isSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGrid_IsSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> bool() +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> bool() %% @equiv isVisible(This,Coords, []) isVisible(This,Coords={CoordsR,CoordsC}) when is_record(This, wx_ref),is_integer(CoordsR),is_integer(CoordsC) -> @@ -1108,7 +1108,7 @@ isVisible(This,Coords={CoordsR,CoordsC}) %% <p><c> %% isVisible(This::wxGrid(), Row::integer(), Col::integer()) -> isVisible(This,Row,Col, []) </c></p> %% <p><c> -%% isVisible(This::wxGrid(), Coords::{R::integer(),C::integer()}, [Option]) -> bool() </c> +%% isVisible(This::wxGrid(), Coords::{R::integer(), C::integer()}, [Option]) -> bool() </c> %%<br /> Option = {wholeCellVisible, bool()} %% </p> @@ -1136,7 +1136,7 @@ isVisible(#wx_ref{type=ThisT,ref=ThisRef},Row,Col, Options) wxe_util:call(?wxGrid_IsVisible_3, <<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> ok +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridmakecellvisible">external documentation</a>. makeCellVisible(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC}) when is_integer(CoordsR),is_integer(CoordsC) -> @@ -1255,13 +1255,13 @@ selectAll(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxGrid_SelectAll, <<ThisRef:32/?UI>>). -%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}) -> ok +%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}) -> ok %% @equiv selectBlock(This,TopLeft,BottomRight, []) selectBlock(This,TopLeft={TopLeftR,TopLeftC},BottomRight={BottomRightR,BottomRightC}) when is_record(This, wx_ref),is_integer(TopLeftR),is_integer(TopLeftC),is_integer(BottomRightR),is_integer(BottomRightC) -> selectBlock(This,TopLeft,BottomRight, []). -%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}, [Option]) -> ok +%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}, [Option]) -> ok %% Option = {addToSelected, bool()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridselectblock">external documentation</a>. selectBlock(#wx_ref{type=ThisT,ref=ThisRef},{TopLeftR,TopLeftC},{BottomRightR,BottomRightC}, Options) @@ -1434,7 +1434,7 @@ setCellTextColour(#wx_ref{type=ThisT,ref=ThisRef},Val,Row,Col) wxe_util:cast(?wxGrid_SetCellTextColour_3_1, <<ThisRef:32/?UI,(wxe_util:colour_bin(Val)):16/binary,Row:32/?UI,Col:32/?UI>>). -%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}, S::string()) -> ok +%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}, S::string()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridsetcellvalue">external documentation</a>. setCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC},S) when is_integer(CoordsR),is_integer(CoordsC),is_list(S) -> diff --git a/lib/wx/src/gen/wxGridBagSizer.erl b/lib/wx/src/gen/wxGridBagSizer.erl index cfc182cf89..d2b8a2b045 100644 --- a/lib/wx/src/gen/wxGridBagSizer.erl +++ b/lib/wx/src/gen/wxGridBagSizer.erl @@ -90,7 +90,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> %% <p><c> %% add(This::wxGridBagSizer(), Width::integer(), Height::integer()) -> add(This,Width,Height, []) </c></p> %% <p><c> -%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}) -> add(This,Window,Pos, []) </c></p> +%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}) -> add(This,Window,Pos, []) </c></p> %% <p><c> %% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), [Option]) -> wxSizerItem:wxSizerItem() </c> %%<br /> Option = {proportion, integer()} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} @@ -125,14 +125,14 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Options %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizeradd">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(),C::integer()}) -> add(This,Width,Height,Pos, []) </c></p> +%% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(), C::integer()}) -> add(This,Width,Height,Pos, []) </c></p> %% <p><c> %% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), [Option]) -> wxSizerItem:wxSizerItem() </c> %%<br /> Option = {proportion, integer()} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} %% </p> %% <p><c> -%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() </c> -%%<br /> Option = {span, {RS::integer(),CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} +%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() </c> +%%<br /> Option = {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} %% </p> add(This,Width,Height,Pos={PosR,PosC}) @@ -167,8 +167,8 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},{PosR,Po wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI,PosR:32/?UI,PosC:32/?UI, BinOpt/binary>>). -%% @spec (This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(),C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() -%% Option = {span, {RS::integer(),CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} +%% @spec (This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(), C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() +%% Option = {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizeradd">external documentation</a>. add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,{PosR,PosC}, Options) when is_integer(Width),is_integer(Height),is_integer(PosR),is_integer(PosC),is_list(Options) -> @@ -182,7 +182,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,{PosR,PosC}, Options) wxe_util:call(?wxGridBagSizer_Add_4, <<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI,PosR:32/?UI,PosC:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxGridBagSizer()) -> {W::integer(),H::integer()} +%% @spec (This::wxGridBagSizer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercalcmin">external documentation</a>. calcMin(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGridBagSizer), @@ -199,7 +199,7 @@ checkForIntersection(This,Item) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercheckforintersection">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% checkForIntersection(This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}, Span::{RS::integer(),CS::integer()}) -> checkForIntersection(This,Pos,Span, []) </c></p> +%% checkForIntersection(This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}, Span::{RS::integer(), CS::integer()}) -> checkForIntersection(This,Pos,Span, []) </c></p> %% <p><c> %% checkForIntersection(This::wxGridBagSizer(), Item::wxGBSizerItem:wxGBSizerItem(), [Option]) -> bool() </c> %%<br /> Option = {excludeItem, wxGBSizerItem:wxGBSizerItem()} @@ -218,7 +218,7 @@ checkForIntersection(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=Item wxe_util:call(?wxGridBagSizer_CheckForIntersection_2, <<ThisRef:32/?UI,ItemRef:32/?UI, BinOpt/binary>>). -%% @spec (This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}, Span::{RS::integer(),CS::integer()}, [Option]) -> bool() +%% @spec (This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}, Span::{RS::integer(), CS::integer()}, [Option]) -> bool() %% Option = {excludeItem, wxGBSizerItem:wxGBSizerItem()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercheckforintersection">external documentation</a>. checkForIntersection(#wx_ref{type=ThisT,ref=ThisRef},{PosR,PosC},{SpanRS,SpanCS}, Options) @@ -243,7 +243,7 @@ findItem(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) -> wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI>>). -%% @spec (This::wxGridBagSizer(), Pt::{X::integer(),Y::integer()}) -> wxGBSizerItem:wxGBSizerItem() +%% @spec (This::wxGridBagSizer(), Pt::{X::integer(), Y::integer()}) -> wxGBSizerItem:wxGBSizerItem() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizerfinditematpoint">external documentation</a>. findItemAtPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -251,7 +251,7 @@ findItemAtPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:call(?wxGridBagSizer_FindItemAtPoint, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}) -> wxGBSizerItem:wxGBSizerItem() +%% @spec (This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}) -> wxGBSizerItem:wxGBSizerItem() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizerfinditematposition">external documentation</a>. findItemAtPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosR,PosC}) when is_integer(PosR),is_integer(PosC) -> @@ -267,7 +267,7 @@ findItemWithData(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=UserDataT,ref=User wxe_util:call(?wxGridBagSizer_FindItemWithData, <<ThisRef:32/?UI,UserDataRef:32/?UI>>). -%% @spec (This::wxGridBagSizer(), Row::integer(), Col::integer()) -> {W::integer(),H::integer()} +%% @spec (This::wxGridBagSizer(), Row::integer(), Col::integer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetcellsize">external documentation</a>. getCellSize(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) when is_integer(Row),is_integer(Col) -> @@ -275,21 +275,21 @@ getCellSize(#wx_ref{type=ThisT,ref=ThisRef},Row,Col) wxe_util:call(?wxGridBagSizer_GetCellSize, <<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>). -%% @spec (This::wxGridBagSizer()) -> {W::integer(),H::integer()} +%% @spec (This::wxGridBagSizer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetemptycellsize">external documentation</a>. getEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGridBagSizer), wxe_util:call(?wxGridBagSizer_GetEmptyCellSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {R::integer(),C::integer()} +%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {R::integer(), C::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetitemposition">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% getItemPosition(This::wxGridBagSizer(), Index::integer()) -> {R::integer(),C::integer()} </c> +%% getItemPosition(This::wxGridBagSizer(), Index::integer()) -> {R::integer(), C::integer()} </c> %% </p> %% <p><c> -%% getItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {R::integer(),C::integer()} </c> +%% getItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {R::integer(), C::integer()} </c> %% </p> getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Index) when is_integer(Index) -> @@ -307,14 +307,14 @@ getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowR wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI>>). -%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {RS::integer(),CS::integer()} +%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {RS::integer(), CS::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetitemspan">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% getItemSpan(This::wxGridBagSizer(), Index::integer()) -> {RS::integer(),CS::integer()} </c> +%% getItemSpan(This::wxGridBagSizer(), Index::integer()) -> {RS::integer(), CS::integer()} </c> %% </p> %% <p><c> -%% getItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {RS::integer(),CS::integer()} </c> +%% getItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {RS::integer(), CS::integer()} </c> %% </p> getItemSpan(#wx_ref{type=ThisT,ref=ThisRef},Index) when is_integer(Index) -> @@ -332,7 +332,7 @@ getItemSpan(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI>>). -%% @spec (This::wxGridBagSizer(), Sz::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxGridBagSizer(), Sz::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetemptycellsize">external documentation</a>. setEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH}) when is_integer(SzW),is_integer(SzH) -> @@ -340,14 +340,14 @@ setEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH}) wxe_util:cast(?wxGridBagSizer_SetEmptyCellSize, <<ThisRef:32/?UI,SzW:32/?UI,SzH:32/?UI>>). -%% @spec (This::wxGridBagSizer(),X::integer()|term(),Pos::{R::integer(),C::integer()}) -> bool() +%% @spec (This::wxGridBagSizer(),X::integer()|term(),Pos::{R::integer(), C::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetitemposition">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% setItemPosition(This::wxGridBagSizer(), Index::integer(), Pos::{R::integer(),C::integer()}) -> bool() </c> +%% setItemPosition(This::wxGridBagSizer(), Index::integer(), Pos::{R::integer(), C::integer()}) -> bool() </c> %% </p> %% <p><c> -%% setItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}) -> bool() </c> +%% setItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}) -> bool() </c> %% </p> setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Index,{PosR,PosC}) when is_integer(Index),is_integer(PosR),is_integer(PosC) -> @@ -366,14 +366,14 @@ setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowR wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI,PosR:32/?UI,PosC:32/?UI>>). -%% @spec (This::wxGridBagSizer(),X::integer()|term(),Span::{RS::integer(),CS::integer()}) -> bool() +%% @spec (This::wxGridBagSizer(),X::integer()|term(),Span::{RS::integer(), CS::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetitemspan">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% setItemSpan(This::wxGridBagSizer(), Index::integer(), Span::{RS::integer(),CS::integer()}) -> bool() </c> +%% setItemSpan(This::wxGridBagSizer(), Index::integer(), Span::{RS::integer(), CS::integer()}) -> bool() </c> %% </p> %% <p><c> -%% setItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Span::{RS::integer(),CS::integer()}) -> bool() </c> +%% setItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Span::{RS::integer(), CS::integer()}) -> bool() </c> %% </p> setItemSpan(#wx_ref{type=ThisT,ref=ThisRef},Index,{SpanRS,SpanCS}) when is_integer(Index),is_integer(SpanRS),is_integer(SpanCS) -> diff --git a/lib/wx/src/gen/wxGridCellAttr.erl b/lib/wx/src/gen/wxGridCellAttr.erl index 3d23c2acfc..a9a0c1fb79 100644 --- a/lib/wx/src/gen/wxGridCellAttr.erl +++ b/lib/wx/src/gen/wxGridCellAttr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -165,7 +165,7 @@ getFont(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGridCellAttr_GetFont, <<ThisRef:32/?UI>>). -%% @spec (This::wxGridCellAttr()) -> {HAlign::integer(),VAlign::integer()} +%% @spec (This::wxGridCellAttr()) -> {HAlign::integer(), VAlign::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellattr.html#wxgridcellattrgetalignment">external documentation</a>. getAlignment(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGridCellAttr), diff --git a/lib/wx/src/gen/wxGridCellEditor.erl b/lib/wx/src/gen/wxGridCellEditor.erl index a27ba7bd0f..de1ebc5a4c 100644 --- a/lib/wx/src/gen/wxGridCellEditor.erl +++ b/lib/wx/src/gen/wxGridCellEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -50,7 +50,7 @@ isCreated(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGridCellEditor_IsCreated, <<ThisRef:32/?UI>>). -%% @spec (This::wxGridCellEditor(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxGridCellEditor(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcelleditor.html#wxgridcelleditorsetsize">external documentation</a>. setSize(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -76,7 +76,7 @@ show(#wx_ref{type=ThisT,ref=ThisRef},Show, Options) wxe_util:cast(?wxGridCellEditor_Show, <<ThisRef:32/?UI,(wxe_util:from_bool(Show)):32/?UI, BinOpt/binary>>). -%% @spec (This::wxGridCellEditor(), RectCell::{X::integer(),Y::integer(),W::integer(),H::integer()}, Attr::wxGridCellAttr:wxGridCellAttr()) -> ok +%% @spec (This::wxGridCellEditor(), RectCell::{X::integer(), Y::integer(), W::integer(), H::integer()}, Attr::wxGridCellAttr:wxGridCellAttr()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcelleditor.html#wxgridcelleditorpaintbackground">external documentation</a>. paintBackground(#wx_ref{type=ThisT,ref=ThisRef},{RectCellX,RectCellY,RectCellW,RectCellH},#wx_ref{type=AttrT,ref=AttrRef}) when is_integer(RectCellX),is_integer(RectCellY),is_integer(RectCellW),is_integer(RectCellH) -> diff --git a/lib/wx/src/gen/wxGridCellRenderer.erl b/lib/wx/src/gen/wxGridCellRenderer.erl index d9520c478f..765c116a48 100644 --- a/lib/wx/src/gen/wxGridCellRenderer.erl +++ b/lib/wx/src/gen/wxGridCellRenderer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -32,7 +32,7 @@ %% @hidden parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, Row::integer(), Col::integer(), IsSelected::bool()) -> ok +%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, Row::integer(), Col::integer(), IsSelected::bool()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellrenderer.html#wxgridcellrendererdraw">external documentation</a>. draw(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{type=AttrT,ref=AttrRef},#wx_ref{type=DcT,ref=DcRef},{RectX,RectY,RectW,RectH},Row,Col,IsSelected) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_integer(Row),is_integer(Col),is_boolean(IsSelected) -> @@ -43,7 +43,7 @@ draw(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{typ wxe_util:cast(?wxGridCellRenderer_Draw, <<ThisRef:32/?UI,GridRef:32/?UI,AttrRef:32/?UI,DcRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,Row:32/?UI,Col:32/?UI,(wxe_util:from_bool(IsSelected)):32/?UI>>). -%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Row::integer(), Col::integer()) -> {W::integer(),H::integer()} +%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Row::integer(), Col::integer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellrenderer.html#wxgridcellrenderergetbestsize">external documentation</a>. getBestSize(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{type=AttrT,ref=AttrRef},#wx_ref{type=DcT,ref=DcRef},Row,Col) when is_integer(Row),is_integer(Col) -> diff --git a/lib/wx/src/gen/wxGridEvent.erl b/lib/wx/src/gen/wxGridEvent.erl index 9b7e0012ca..123088afb5 100644 --- a/lib/wx/src/gen/wxGridEvent.erl +++ b/lib/wx/src/gen/wxGridEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -69,7 +69,7 @@ getCol(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxGridEvent_GetCol, <<ThisRef:32/?UI>>). -%% @spec (This::wxGridEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxGridEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridevent.html#wxgrideventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGridEvent), diff --git a/lib/wx/src/gen/wxHelpEvent.erl b/lib/wx/src/gen/wxHelpEvent.erl index ef3c666ab7..b80903c314 100644 --- a/lib/wx/src/gen/wxHelpEvent.erl +++ b/lib/wx/src/gen/wxHelpEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -50,7 +50,7 @@ getOrigin(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxHelpEvent_GetOrigin, <<ThisRef:32/?UI>>). -%% @spec (This::wxHelpEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxHelpEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhelpevent.html#wxhelpeventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxHelpEvent), @@ -67,7 +67,7 @@ setOrigin(#wx_ref{type=ThisT,ref=ThisRef},Origin) wxe_util:cast(?wxHelpEvent_SetOrigin, <<ThisRef:32/?UI,Origin:32/?UI>>). -%% @spec (This::wxHelpEvent(), Pos::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxHelpEvent(), Pos::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhelpevent.html#wxhelpeventsetposition">external documentation</a>. setPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) when is_integer(PosX),is_integer(PosY) -> diff --git a/lib/wx/src/gen/wxHtmlWindow.erl b/lib/wx/src/gen/wxHtmlWindow.erl index ba8278ff56..891e5481fb 100644 --- a/lib/wx/src/gen/wxHtmlWindow.erl +++ b/lib/wx/src/gen/wxHtmlWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -99,7 +99,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxHtmlWindow() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowwxhtmlwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -217,7 +217,7 @@ selectionToText(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxHtmlWindow_SelectionToText, <<ThisRef:32/?UI>>). -%% @spec (This::wxHtmlWindow(), Pos::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxHtmlWindow(), Pos::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowselectline">external documentation</a>. selectLine(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) when is_integer(PosX),is_integer(PosY) -> @@ -225,7 +225,7 @@ selectLine(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) wxe_util:cast(?wxHtmlWindow_SelectLine, <<ThisRef:32/?UI,PosX:32/?UI,PosY:32/?UI>>). -%% @spec (This::wxHtmlWindow(), Pos::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxHtmlWindow(), Pos::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowselectword">external documentation</a>. selectWord(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY}) when is_integer(PosX),is_integer(PosY) -> diff --git a/lib/wx/src/gen/wxIconBundle.erl b/lib/wx/src/gen/wxIconBundle.erl index ee133cbcb9..011b2dd1ac 100644 --- a/lib/wx/src/gen/wxIconBundle.erl +++ b/lib/wx/src/gen/wxIconBundle.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ getIcon(This) %%<br /> Option = {size, integer()} %% </p> %% <p><c> -%% getIcon(This::wxIconBundle(), Size::{W::integer(),H::integer()}) -> wxIcon:wxIcon() </c> +%% getIcon(This::wxIconBundle(), Size::{W::integer(), H::integer()}) -> wxIcon:wxIcon() </c> %% </p> getIcon(#wx_ref{type=ThisT,ref=ThisRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxImage.erl b/lib/wx/src/gen/wxImage.erl index 5fe105fbb2..ea41a78a40 100644 --- a/lib/wx/src/gen/wxImage.erl +++ b/lib/wx/src/gen/wxImage.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -303,13 +303,13 @@ create(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,Data,Alpha, Options) wxe_util:cast(?wxImage_Destroy, <<ThisRef:32/?UI>>). -%% @spec (This::wxImage()) -> {bool(),R::integer(),G::integer(),B::integer()} +%% @spec (This::wxImage()) -> {bool(), R::integer(), G::integer(), B::integer()} %% @equiv findFirstUnusedColour(This, []) findFirstUnusedColour(This) when is_record(This, wx_ref) -> findFirstUnusedColour(This, []). -%% @spec (This::wxImage(), [Option]) -> {bool(),R::integer(),G::integer(),B::integer()} +%% @spec (This::wxImage(), [Option]) -> {bool(), R::integer(), G::integer(), B::integer()} %% Option = {startR, integer()} | {startG, integer()} | {startB, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagefindfirstunusedcolour">external documentation</a>. findFirstUnusedColour(#wx_ref{type=ThisT,ref=ThisRef}, Options) @@ -413,7 +413,7 @@ getMaskRed(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxImage_GetMaskRed, <<ThisRef:32/?UI>>). -%% @spec (This::wxImage()) -> {bool(),R::integer(),G::integer(),B::integer()} +%% @spec (This::wxImage()) -> {bool(), R::integer(), G::integer(), B::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagegetorfindmaskcolour">external documentation</a>. getOrFindMaskColour(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxImage), @@ -435,7 +435,7 @@ getRed(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:call(?wxImage_GetRed, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxImage(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> wxImage() +%% @spec (This::wxImage(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> wxImage() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagegetsubimage">external documentation</a>. getSubImage(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> @@ -615,13 +615,13 @@ rescale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options) wxe_util:call(?wxImage_Rescale, <<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}) -> wxImage() +%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}) -> wxImage() %% @equiv resize(This,Size,Pos, []) resize(This,Size={SizeW,SizeH},Pos={PosX,PosY}) when is_record(This, wx_ref),is_integer(SizeW),is_integer(SizeH),is_integer(PosX),is_integer(PosY) -> resize(This,Size,Pos, []). -%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}, [Option]) -> wxImage() +%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}, [Option]) -> wxImage() %% Option = {r, integer()} | {g, integer()} | {b, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximageresize">external documentation</a>. resize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options) @@ -635,14 +635,14 @@ resize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options) wxe_util:call(?wxImage_Resize, <<ThisRef:32/?UI,SizeW:32/?UI,SizeH:32/?UI,PosX:32/?UI,PosY:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(),Y::integer()}) -> wxImage() +%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(), Y::integer()}) -> wxImage() %% @equiv rotate(This,Angle,Centre_of_rotation, []) rotate(This,Angle,Centre_of_rotation={Centre_of_rotationX,Centre_of_rotationY}) when is_record(This, wx_ref),is_float(Angle),is_integer(Centre_of_rotationX),is_integer(Centre_of_rotationY) -> rotate(This,Angle,Centre_of_rotation, []). -%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(),Y::integer()}, [Option]) -> wxImage() -%% Option = {interpolating, bool()} | {offset_after_rotation, {X::integer(),Y::integer()}} +%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(), Y::integer()}, [Option]) -> wxImage() +%% Option = {interpolating, bool()} | {offset_after_rotation, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagerotate">external documentation</a>. rotate(#wx_ref{type=ThisT,ref=ThisRef},Angle,{Centre_of_rotationX,Centre_of_rotationY}, Options) when is_float(Angle),is_integer(Centre_of_rotationX),is_integer(Centre_of_rotationY),is_list(Options) -> @@ -730,13 +730,13 @@ scale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options) wxe_util:call(?wxImage_Scale, <<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}) -> wxImage() +%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}) -> wxImage() %% @equiv size(This,Size,Pos, []) size(This,Size={SizeW,SizeH},Pos={PosX,PosY}) when is_record(This, wx_ref),is_integer(SizeW),is_integer(SizeH),is_integer(PosX),is_integer(PosY) -> size(This,Size,Pos, []). -%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}, [Option]) -> wxImage() +%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}, [Option]) -> wxImage() %% Option = {r, integer()} | {g, integer()} | {b, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagesize">external documentation</a>. size(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options) @@ -881,7 +881,7 @@ setPalette(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PaletteT,ref=PaletteRef} wxe_util:cast(?wxImage_SetPalette, <<ThisRef:32/?UI,PaletteRef:32/?UI>>). -%% @spec (This::wxImage(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, R::integer(), G::integer(), B::integer()) -> ok +%% @spec (This::wxImage(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, R::integer(), G::integer(), B::integer()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagesetrgb">external documentation</a>. setRGB(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},R,G,B) when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_integer(R),is_integer(G),is_integer(B) -> diff --git a/lib/wx/src/gen/wxImageList.erl b/lib/wx/src/gen/wxImageList.erl index dbd51bc47b..f805a234df 100644 --- a/lib/wx/src/gen/wxImageList.erl +++ b/lib/wx/src/gen/wxImageList.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -150,7 +150,7 @@ getImageCount(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxImageList_GetImageCount, <<ThisRef:32/?UI>>). -%% @spec (This::wxImageList(), Index::integer()) -> {bool(),Width::integer(),Height::integer()} +%% @spec (This::wxImageList(), Index::integer()) -> {bool(), Width::integer(), Height::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximagelist.html#wximagelistgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef},Index) when is_integer(Index) -> diff --git a/lib/wx/src/gen/wxJoystickEvent.erl b/lib/wx/src/gen/wxJoystickEvent.erl index 2c2d7f3968..2f149a50f8 100644 --- a/lib/wx/src/gen/wxJoystickEvent.erl +++ b/lib/wx/src/gen/wxJoystickEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -118,7 +118,7 @@ getJoystick(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxJoystickEvent_GetJoystick, <<ThisRef:32/?UI>>). -%% @spec (This::wxJoystickEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxJoystickEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxjoystickevent.html#wxjoystickeventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxJoystickEvent), diff --git a/lib/wx/src/gen/wxKeyEvent.erl b/lib/wx/src/gen/wxKeyEvent.erl index 00d1e2033a..edda5ee0a6 100644 --- a/lib/wx/src/gen/wxKeyEvent.erl +++ b/lib/wx/src/gen/wxKeyEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,7 +78,7 @@ getModifiers(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxKeyEvent_GetModifiers, <<ThisRef:32/?UI>>). -%% @spec (This::wxKeyEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxKeyEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxkeyevent.html#wxkeyeventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxKeyEvent), diff --git a/lib/wx/src/gen/wxLayoutAlgorithm.erl b/lib/wx/src/gen/wxLayoutAlgorithm.erl index 402d116338..c17abeaed1 100644 --- a/lib/wx/src/gen/wxLayoutAlgorithm.erl +++ b/lib/wx/src/gen/wxLayoutAlgorithm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -65,7 +65,7 @@ layoutMDIFrame(This,Frame) layoutMDIFrame(This,Frame, []). %% @spec (This::wxLayoutAlgorithm(), Frame::wxMDIParentFrame:wxMDIParentFrame(), [Option]) -> bool() -%% Option = {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}} +%% Option = {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlayoutalgorithm.html#wxlayoutalgorithmlayoutmdiframe">external documentation</a>. layoutMDIFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FrameT,ref=FrameRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxListBox.erl b/lib/wx/src/gen/wxListBox.erl index 731209c586..cc30bf95e4 100644 --- a/lib/wx/src/gen/wxListBox.erl +++ b/lib/wx/src/gen/wxListBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxListBox() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxwxlistbox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -109,13 +109,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) wxe_util:construct(?wxListBox_new_3, <<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>). -%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool() +%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool() %% @equiv create(This,Parent,Id,Pos,Size,Choices, []) create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) -> create(This,Parent,Id,Pos,Size,Choices, []). -%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool() +%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool() %% Option = {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options) @@ -139,7 +139,7 @@ deselect(#wx_ref{type=ThisT,ref=ThisRef},N) wxe_util:cast(?wxListBox_Deselect, <<ThisRef:32/?UI,N:32/?UI>>). -%% @spec (This::wxListBox()) -> {integer(),ASelections::[integer()]} +%% @spec (This::wxListBox()) -> {integer(), ASelections::[integer()]} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxgetselections">external documentation</a>. getSelections(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxListBox), @@ -174,7 +174,7 @@ set(#wx_ref{type=ThisT,ref=ThisRef},Items) wxe_util:cast(?wxListBox_Set, <<ThisRef:32/?UI,(length(Items_UCA)):32/?UI, (<< <<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>|| UC_Str <- Items_UCA>>)/binary, 0:(((8- ((0 + lists:sum([byte_size(S)+4||S<-Items_UCA])) band 16#7)) band 16#7))/unit:8>>). -%% @spec (This::wxListBox(), Point::{X::integer(),Y::integer()}) -> integer() +%% @spec (This::wxListBox(), Point::{X::integer(), Y::integer()}) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY}) when is_integer(PointX),is_integer(PointY) -> diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl index 5799206b87..fa99897171 100644 --- a/lib/wx/src/gen/wxListCtrl.erl +++ b/lib/wx/src/gen/wxListCtrl.erl @@ -263,7 +263,7 @@ findItem(This,Start,Str) %%<br /> Option = {partial, bool()} %% </p> %% <p><c> -%% findItem(This::wxListCtrl(), Start::integer(), Pt::{X::integer(),Y::integer()}, Direction::integer()) -> integer() </c> +%% findItem(This::wxListCtrl(), Start::integer(), Pt::{X::integer(), Y::integer()}, Direction::integer()) -> integer() </c> %% </p> findItem(#wx_ref{type=ThisT,ref=ThisRef},Start,Str, Options) when is_integer(Start),is_list(Str),is_list(Options) -> @@ -365,7 +365,7 @@ getItemFont(#wx_ref{type=ThisT,ref=ThisRef},Item) wxe_util:call(?wxListCtrl_GetItemFont, <<ThisRef:32/?UI,Item:32/?UI>>). -%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(),Y::integer()}) -> bool() +%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(), Y::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemposition">external documentation</a>. getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY}) when is_integer(Item),is_integer(PosX),is_integer(PosY) -> @@ -373,13 +373,13 @@ getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY}) wxe_util:call(?wxListCtrl_GetItemPosition, <<ThisRef:32/?UI,Item:32/?UI,PosX:32/?UI,PosY:32/?UI>>). -%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() +%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() %% @equiv getItemRect(This,Item,Rect, []) getItemRect(This,Item,Rect={RectX,RectY,RectW,RectH}) when is_record(This, wx_ref),is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> getItemRect(This,Item,Rect, []). -%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> bool() +%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> bool() %% Option = {code, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemrect">external documentation</a>. getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Options) @@ -391,7 +391,7 @@ getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Opti wxe_util:call(?wxListCtrl_GetItemRect, <<ThisRef:32/?UI,Item:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI, BinOpt/binary>>). -%% @spec (This::wxListCtrl()) -> {W::integer(),H::integer()} +%% @spec (This::wxListCtrl()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemspacing">external documentation</a>. getItemSpacing(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxListCtrl), @@ -462,14 +462,14 @@ getTopItem(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxListCtrl_GetTopItem, <<ThisRef:32/?UI>>). -%% @spec (This::wxListCtrl()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxListCtrl()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetviewrect">external documentation</a>. getViewRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxListCtrl), wxe_util:call(?wxListCtrl_GetViewRect, <<ThisRef:32/?UI>>). -%% @spec (This::wxListCtrl(), Point::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxListCtrl(), Point::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY}) when is_integer(PointX),is_integer(PointY) -> @@ -692,7 +692,7 @@ setItemColumnImage(#wx_ref{type=ThisT,ref=ThisRef},Item,Column,Image) wxe_util:call(?wxListCtrl_SetItemColumnImage, <<ThisRef:32/?UI,Item:32/?UI,Column:32/?UI,Image:32/?UI>>). -%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(),Y::integer()}) -> bool() +%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(), Y::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlsetitemposition">external documentation</a>. setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY}) when is_integer(Item),is_integer(PosX),is_integer(PosY) -> diff --git a/lib/wx/src/gen/wxListEvent.erl b/lib/wx/src/gen/wxListEvent.erl index 74f9e6095c..f7d8658acc 100644 --- a/lib/wx/src/gen/wxListEvent.erl +++ b/lib/wx/src/gen/wxListEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -83,7 +83,7 @@ getColumn(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxListEvent_GetColumn, <<ThisRef:32/?UI>>). -%% @spec (This::wxListEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxListEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistevent.html#wxlisteventgetpoint">external documentation</a>. getPoint(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxListEvent), diff --git a/lib/wx/src/gen/wxListbook.erl b/lib/wx/src/gen/wxListbook.erl index b1f0e3d9a4..c204dc87a1 100644 --- a/lib/wx/src/gen/wxListbook.erl +++ b/lib/wx/src/gen/wxListbook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxListbook() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookwxlistbook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -160,7 +160,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxListbook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxListbook_GetSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxListbook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxListbook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi wxe_util:cast(?wxListbook_SetImageList, <<ThisRef:32/?UI,ImageListRef:32/?UI>>). -%% @spec (This::wxListbook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxListbook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbooksetpagesize">external documentation</a>. setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxMDIChildFrame.erl b/lib/wx/src/gen/wxMDIChildFrame.erl index 34edac4213..d3e1edda55 100644 --- a/lib/wx/src/gen/wxMDIChildFrame.erl +++ b/lib/wx/src/gen/wxMDIChildFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -100,7 +100,7 @@ new(Parent,Id,Title) new(Parent,Id,Title, []). %% @spec (Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::string(), [Option]) -> wxMDIChildFrame() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdichildframe.html#wxmdichildframewxmdichildframe">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -128,7 +128,7 @@ create(This,Parent,Id,Title) create(This,Parent,Id,Title, []). %% @spec (This::wxMDIChildFrame(), Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdichildframe.html#wxmdichildframecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> diff --git a/lib/wx/src/gen/wxMDIParentFrame.erl b/lib/wx/src/gen/wxMDIParentFrame.erl index db47e7ac74..7f8a305876 100644 --- a/lib/wx/src/gen/wxMDIParentFrame.erl +++ b/lib/wx/src/gen/wxMDIParentFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -102,7 +102,7 @@ new(Parent,Id,Title) new(Parent,Id,Title, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxMDIParentFrame() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdiparentframe.html#wxmdiparentframewxmdiparentframe">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -151,7 +151,7 @@ create(This,Parent,Id,Title) create(This,Parent,Id,Title, []). %% @spec (This::wxMDIParentFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdiparentframe.html#wxmdiparentframecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> diff --git a/lib/wx/src/gen/wxMessageDialog.erl b/lib/wx/src/gen/wxMessageDialog.erl index 916b201d3f..d13bb7cb6e 100644 --- a/lib/wx/src/gen/wxMessageDialog.erl +++ b/lib/wx/src/gen/wxMessageDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent,Message) new(Parent,Message, []). %% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxMessageDialog() -%% Option = {caption, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} +%% Option = {caption, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmessagedialog.html#wxmessagedialogwxmessagedialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options) when is_list(Message),is_list(Options) -> diff --git a/lib/wx/src/gen/wxMiniFrame.erl b/lib/wx/src/gen/wxMiniFrame.erl index b86f1d7cfa..108ebcfb0e 100644 --- a/lib/wx/src/gen/wxMiniFrame.erl +++ b/lib/wx/src/gen/wxMiniFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -100,7 +100,7 @@ new(Parent,Id,Title) new(Parent,Id,Title, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxMiniFrame() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxminiframe.html#wxminiframewxminiframe">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> @@ -121,7 +121,7 @@ create(This,Parent,Id,Title) create(This,Parent,Id,Title, []). %% @spec (This::wxMiniFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxminiframe.html#wxminiframecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options) when is_integer(Id),is_list(Title),is_list(Options) -> diff --git a/lib/wx/src/gen/wxMouseEvent.erl b/lib/wx/src/gen/wxMouseEvent.erl index fed9a33db7..a91d2a2e99 100644 --- a/lib/wx/src/gen/wxMouseEvent.erl +++ b/lib/wx/src/gen/wxMouseEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -151,14 +151,14 @@ getButton(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxMouseEvent_GetButton, <<ThisRef:32/?UI>>). -%% @spec (This::wxMouseEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxMouseEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmouseevent.html#wxmouseeventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxMouseEvent), wxe_util:call(?wxMouseEvent_GetPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxMouseEvent(), Dc::wxDC:wxDC()) -> {X::integer(),Y::integer()} +%% @spec (This::wxMouseEvent(), Dc::wxDC:wxDC()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmouseevent.html#wxmouseeventgetlogicalposition">external documentation</a>. getLogicalPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef}) -> ?CLASS(ThisT,wxMouseEvent), diff --git a/lib/wx/src/gen/wxMoveEvent.erl b/lib/wx/src/gen/wxMoveEvent.erl index 80bf59074a..97cf803310 100644 --- a/lib/wx/src/gen/wxMoveEvent.erl +++ b/lib/wx/src/gen/wxMoveEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,7 +41,7 @@ parent_class(wxEvent) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxMoveEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxMoveEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmoveevent.html#wxmoveeventgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxMoveEvent), diff --git a/lib/wx/src/gen/wxMultiChoiceDialog.erl b/lib/wx/src/gen/wxMultiChoiceDialog.erl index e69889a1e0..6fae0c4860 100644 --- a/lib/wx/src/gen/wxMultiChoiceDialog.erl +++ b/lib/wx/src/gen/wxMultiChoiceDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -97,7 +97,7 @@ new(Parent,Message,Caption,Choices) new(Parent,Message,Caption,Choices, []). %% @spec (Parent::wxWindow:wxWindow(), Message::string(), Caption::string(), Choices::[[string()]], [Option]) -> wxMultiChoiceDialog() -%% Option = {style, integer()} | {pos, {X::integer(),Y::integer()}} +%% Option = {style, integer()} | {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmultichoicedialog.html#wxmultichoicedialogwxmultichoicedialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options) when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) -> diff --git a/lib/wx/src/gen/wxNotebook.erl b/lib/wx/src/gen/wxNotebook.erl index da543d7ac6..b918de5bb4 100644 --- a/lib/wx/src/gen/wxNotebook.erl +++ b/lib/wx/src/gen/wxNotebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent,Winid) new(Parent,Winid, []). %% @spec (Parent::wxWindow:wxWindow(), Winid::integer(), [Option]) -> wxNotebook() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookwxnotebook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Winid, Options) when is_integer(Winid),is_list(Options) -> @@ -160,7 +160,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxNotebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -263,7 +263,7 @@ getThemeBackgroundColour(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxNotebook_GetThemeBackgroundColour, <<ThisRef:32/?UI>>). -%% @spec (This::wxNotebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxNotebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -300,7 +300,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi wxe_util:cast(?wxNotebook_SetImageList, <<ThisRef:32/?UI,ImageListRef:32/?UI>>). -%% @spec (This::wxNotebook(), Padding::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxNotebook(), Padding::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebooksetpadding">external documentation</a>. setPadding(#wx_ref{type=ThisT,ref=ThisRef},{PaddingW,PaddingH}) when is_integer(PaddingW),is_integer(PaddingH) -> @@ -308,7 +308,7 @@ setPadding(#wx_ref{type=ThisT,ref=ThisRef},{PaddingW,PaddingH}) wxe_util:cast(?wxNotebook_SetPadding, <<ThisRef:32/?UI,PaddingW:32/?UI,PaddingH:32/?UI>>). -%% @spec (This::wxNotebook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxNotebook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebooksetpagesize">external documentation</a>. setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxPageSetupDialogData.erl b/lib/wx/src/gen/wxPageSetupDialogData.erl index 672ec7c083..00b4ca2a36 100644 --- a/lib/wx/src/gen/wxPageSetupDialogData.erl +++ b/lib/wx/src/gen/wxPageSetupDialogData.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -146,28 +146,28 @@ getDefaultInfo(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxPageSetupDialogData_GetDefaultInfo, <<ThisRef:32/?UI>>). -%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetmargintopleft">external documentation</a>. getMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPageSetupDialogData), wxe_util:call(?wxPageSetupDialogData_GetMarginTopLeft, <<ThisRef:32/?UI>>). -%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetmarginbottomright">external documentation</a>. getMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPageSetupDialogData), wxe_util:call(?wxPageSetupDialogData_GetMarginBottomRight, <<ThisRef:32/?UI>>). -%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetminmargintopleft">external documentation</a>. getMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPageSetupDialogData), wxe_util:call(?wxPageSetupDialogData_GetMinMarginTopLeft, <<ThisRef:32/?UI>>). -%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetminmarginbottomright">external documentation</a>. getMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPageSetupDialogData), @@ -181,7 +181,7 @@ getPaperId(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxPageSetupDialogData_GetPaperId, <<ThisRef:32/?UI>>). -%% @spec (This::wxPageSetupDialogData()) -> {W::integer(),H::integer()} +%% @spec (This::wxPageSetupDialogData()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetpapersize">external documentation</a>. getPaperSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPageSetupDialogData), @@ -218,7 +218,7 @@ setDefaultMinMargins(#wx_ref{type=ThisT,ref=ThisRef},Flag) wxe_util:cast(?wxPageSetupDialogData_SetDefaultMinMargins, <<ThisRef:32/?UI,(wxe_util:from_bool(Flag)):32/?UI>>). -%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetmargintopleft">external documentation</a>. setMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -226,7 +226,7 @@ setMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:cast(?wxPageSetupDialogData_SetMarginTopLeft, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetmarginbottomright">external documentation</a>. setMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -234,7 +234,7 @@ setMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:cast(?wxPageSetupDialogData_SetMarginBottomRight, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetminmargintopleft">external documentation</a>. setMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -242,7 +242,7 @@ setMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:cast(?wxPageSetupDialogData_SetMinMarginTopLeft, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetminmarginbottomright">external documentation</a>. setMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -265,7 +265,7 @@ setPaperId(#wx_ref{type=ThisT,ref=ThisRef},Id) %% setPaperSize(This::wxPageSetupDialogData(), Id::integer()) -> ok </c> %% </p> %% <p><c> -%% setPaperSize(This::wxPageSetupDialogData(), Sz::{W::integer(),H::integer()}) -> ok </c> +%% setPaperSize(This::wxPageSetupDialogData(), Sz::{W::integer(), H::integer()}) -> ok </c> %% </p> setPaperSize(#wx_ref{type=ThisT,ref=ThisRef},Id) when is_integer(Id) -> diff --git a/lib/wx/src/gen/wxPalette.erl b/lib/wx/src/gen/wxPalette.erl index ee1fd0016d..3d8e811988 100644 --- a/lib/wx/src/gen/wxPalette.erl +++ b/lib/wx/src/gen/wxPalette.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -75,7 +75,7 @@ getPixel(#wx_ref{type=ThisT,ref=ThisRef},Red,Green,Blue) wxe_util:call(?wxPalette_GetPixel, <<ThisRef:32/?UI,Red:32/?UI,Green:32/?UI,Blue:32/?UI>>). -%% @spec (This::wxPalette(), Pixel::integer()) -> {bool(),Red::integer(),Green::integer(),Blue::integer()} +%% @spec (This::wxPalette(), Pixel::integer()) -> {bool(), Red::integer(), Green::integer(), Blue::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpalette.html#wxpalettegetrgb">external documentation</a>. getRGB(#wx_ref{type=ThisT,ref=ThisRef},Pixel) when is_integer(Pixel) -> diff --git a/lib/wx/src/gen/wxPanel.erl b/lib/wx/src/gen/wxPanel.erl index 55eaa9f404..59fba03102 100644 --- a/lib/wx/src/gen/wxPanel.erl +++ b/lib/wx/src/gen/wxPanel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -86,7 +86,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxPanel() -%% Option = {winid, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {winid, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpanel.html#wxpanelwxpanel">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxPasswordEntryDialog.erl b/lib/wx/src/gen/wxPasswordEntryDialog.erl index f79734ab46..07a0bcef56 100644 --- a/lib/wx/src/gen/wxPasswordEntryDialog.erl +++ b/lib/wx/src/gen/wxPasswordEntryDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Message) new(Parent,Message, []). %% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxPasswordEntryDialog() -%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} +%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpasswordentrydialog.html#wxpasswordentrydialogwxpasswordentrydialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options) when is_list(Message),is_list(Options) -> diff --git a/lib/wx/src/gen/wxPreviewControlBar.erl b/lib/wx/src/gen/wxPreviewControlBar.erl index 78d46d1b95..e85af625e2 100644 --- a/lib/wx/src/gen/wxPreviewControlBar.erl +++ b/lib/wx/src/gen/wxPreviewControlBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -83,7 +83,7 @@ new(Preview,Buttons,Parent) new(Preview,Buttons,Parent, []). %% @spec (Preview::wxPrintPreview:wxPrintPreview(), Buttons::integer(), Parent::wxWindow:wxWindow(), [Option]) -> wxPreviewControlBar() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpreviewcontrolbar.html#wxpreviewcontrolbarwxpreviewcontrolbar">external documentation</a>. new(#wx_ref{type=PreviewT,ref=PreviewRef},Buttons,#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_integer(Buttons),is_list(Options) -> diff --git a/lib/wx/src/gen/wxPreviewFrame.erl b/lib/wx/src/gen/wxPreviewFrame.erl index 91a32e9889..da43f86030 100644 --- a/lib/wx/src/gen/wxPreviewFrame.erl +++ b/lib/wx/src/gen/wxPreviewFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ new(Preview,Parent) new(Preview,Parent, []). %% @spec (Preview::wxPrintPreview:wxPrintPreview(), Parent::wxWindow:wxWindow(), [Option]) -> wxPreviewFrame() -%% Option = {title, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {title, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpreviewframe.html#wxpreviewframewxpreviewframe">external documentation</a>. new(#wx_ref{type=PreviewT,ref=PreviewRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxPrintout.erl b/lib/wx/src/gen/wxPrintout.erl index b5b93921e6..a34c030275 100644 --- a/lib/wx/src/gen/wxPrintout.erl +++ b/lib/wx/src/gen/wxPrintout.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -125,35 +125,35 @@ getDC(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxPrintout_GetDC, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {W::integer(),H::integer()} +%% @spec (This::wxPrintout()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpagesizemm">external documentation</a>. getPageSizeMM(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetPageSizeMM, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {W::integer(),H::integer()} +%% @spec (This::wxPrintout()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpagesizepixels">external documentation</a>. getPageSizePixels(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetPageSizePixels, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpaperrectpixels">external documentation</a>. getPaperRectPixels(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetPaperRectPixels, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetppiprinter">external documentation</a>. getPPIPrinter(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetPPIPrinter, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer()} +%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetppiscreen">external documentation</a>. getPPIScreen(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), @@ -174,7 +174,7 @@ isPreview(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxPrintout_IsPreview, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopaper">external documentation</a>. fitThisSizeToPaper(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH}) when is_integer(ImageSizeW),is_integer(ImageSizeH) -> @@ -182,7 +182,7 @@ fitThisSizeToPaper(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH}) wxe_util:cast(?wxPrintout_FitThisSizeToPaper, <<ThisRef:32/?UI,ImageSizeW:32/?UI,ImageSizeH:32/?UI>>). -%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopage">external documentation</a>. fitThisSizeToPage(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH}) when is_integer(ImageSizeW),is_integer(ImageSizeH) -> @@ -190,7 +190,7 @@ fitThisSizeToPage(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH}) wxe_util:cast(?wxPrintout_FitThisSizeToPage, <<ThisRef:32/?UI,ImageSizeW:32/?UI,ImageSizeH:32/?UI>>). -%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}, PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> ok +%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}, PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopagemargins">external documentation</a>. fitThisSizeToPageMargins(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH},#wx_ref{type=PageSetupDataT,ref=PageSetupDataRef}) when is_integer(ImageSizeW),is_integer(ImageSizeH) -> @@ -228,21 +228,21 @@ mapScreenSizeToDevice(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxPrintout_MapScreenSizeToDevice, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpaperrect">external documentation</a>. getLogicalPaperRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetLogicalPaperRect, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpagerect">external documentation</a>. getLogicalPageRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxPrintout), wxe_util:call(?wxPrintout_GetLogicalPageRect, <<ThisRef:32/?UI>>). -%% @spec (This::wxPrintout(), PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxPrintout(), PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpagemarginsrect">external documentation</a>. getLogicalPageMarginsRect(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageSetupDataT,ref=PageSetupDataRef}) -> ?CLASS(ThisT,wxPrintout), diff --git a/lib/wx/src/gen/wxRadioBox.erl b/lib/wx/src/gen/wxRadioBox.erl index 06e8833972..766a691108 100644 --- a/lib/wx/src/gen/wxRadioBox.erl +++ b/lib/wx/src/gen/wxRadioBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,13 +78,13 @@ parent_class(wxWindow) -> true; parent_class(wxEvtHandler) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> wxRadioBox() +%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> wxRadioBox() %% @equiv new(Parent,Id,Title,Pos,Size,Choices, []) new(Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) when is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) -> new(Parent,Id,Title,Pos,Size,Choices, []). -%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> wxRadioBox() +%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> wxRadioBox() %% Option = {majorDim, integer()} | {style, integer()} | {val, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxwxradiobox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options) @@ -101,13 +101,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choic wxe_util:construct(?wxRadioBox_new, <<ParentRef:32/?UI,Id:32/?UI,(byte_size(Title_UC)):32/?UI,(Title_UC)/binary, 0:(((8- ((4+byte_size(Title_UC)) band 16#7)) band 16#7))/unit:8,PosX:32/?UI,PosY:32/?UI,SizeW:32/?UI,SizeH:32/?UI,(length(Choices_UCA)):32/?UI, (<< <<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>|| UC_Str <- Choices_UCA>>)/binary, 0:(((8- ((4 + lists:sum([byte_size(S)+4||S<-Choices_UCA])) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>). -%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool() +%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool() %% @equiv create(This,Parent,Id,Title,Pos,Size,Choices, []) create(This,Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) -> create(This,Parent,Id,Title,Pos,Size,Choices, []). -%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool() +%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool() %% Option = {majorDim, integer()} | {style, integer()} | {val, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options) @@ -251,7 +251,7 @@ getItemToolTip(#wx_ref{type=ThisT,ref=ThisRef},Item) wxe_util:call(?wxRadioBox_GetItemToolTip, <<ThisRef:32/?UI,Item:32/?UI>>). -%% @spec (This::wxRadioBox(), Pt::{X::integer(),Y::integer()}) -> integer() +%% @spec (This::wxRadioBox(), Pt::{X::integer(), Y::integer()}) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxgetitemfrompoint">external documentation</a>. getItemFromPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> diff --git a/lib/wx/src/gen/wxRadioButton.erl b/lib/wx/src/gen/wxRadioButton.erl index c2c5a00be6..c4665837b5 100644 --- a/lib/wx/src/gen/wxRadioButton.erl +++ b/lib/wx/src/gen/wxRadioButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxRadioButton() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobutton.html#wxradiobuttonwxradiobutton">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> @@ -110,7 +110,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxRadioButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobutton.html#wxradiobuttoncreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> diff --git a/lib/wx/src/gen/wxRegion.erl b/lib/wx/src/gen/wxRegion.erl index 4e8d98a54f..9107a4d6b1 100644 --- a/lib/wx/src/gen/wxRegion.erl +++ b/lib/wx/src/gen/wxRegion.erl @@ -59,7 +59,7 @@ new({RectX,RectY,RectW,RectH}) wxe_util:construct(?wxRegion_new_1_1, <<RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>). -%% @spec (TopLeft::{X::integer(),Y::integer()}, BottomRight::{X::integer(),Y::integer()}) -> wxRegion() +%% @spec (TopLeft::{X::integer(), Y::integer()}, BottomRight::{X::integer(), Y::integer()}) -> wxRegion() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregionwxregion">external documentation</a>. new({TopLeftX,TopLeftY},{BottomRightX,BottomRightY}) when is_integer(TopLeftX),is_integer(TopLeftY),is_integer(BottomRightX),is_integer(BottomRightY) -> @@ -84,12 +84,12 @@ clear(#wx_ref{type=ThisT,ref=ThisRef}) -> %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregioncontains">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% contains(This::wxRegion(), Pt::{X::integer(),Y::integer()}) -> WxRegionContain </c> +%% contains(This::wxRegion(), Pt::{X::integer(), Y::integer()}) -> WxRegionContain </c> %%<br /> WxRegionContain = integer() %%<br /> WxRegionContain is one of ?wxOutRegion | ?wxPartRegion | ?wxInRegion %% </p> %% <p><c> -%% contains(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> WxRegionContain </c> +%% contains(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> WxRegionContain </c> %%<br /> WxRegionContain = integer() %%<br /> WxRegionContain is one of ?wxOutRegion | ?wxPartRegion | ?wxInRegion %% </p> @@ -131,7 +131,7 @@ convertToBitmap(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxRegion_ConvertToBitmap, <<ThisRef:32/?UI>>). -%% @spec (This::wxRegion()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxRegion()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregiongetbox">external documentation</a>. getBox(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxRegion), @@ -145,7 +145,7 @@ getBox(#wx_ref{type=ThisT,ref=ThisRef}) -> %% intersect(This::wxRegion(), Region::wxRegion()) -> bool() </c> %% </p> %% <p><c> -%% intersect(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c> +%% intersect(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c> %% </p> intersect(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) -> ?CLASS(ThisT,wxRegion), @@ -180,7 +180,7 @@ isEmpty(#wx_ref{type=ThisT,ref=ThisRef}) -> %% subtract(This::wxRegion(), Region::wxRegion()) -> bool() </c> %% </p> %% <p><c> -%% subtract(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c> +%% subtract(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c> %% </p> subtract(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) -> ?CLASS(ThisT,wxRegion), @@ -201,7 +201,7 @@ subtract(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H) wxe_util:call(?wxRegion_Subtract_4, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,W:32/?UI,H:32/?UI>>). -%% @spec (This::wxRegion(), Pt::{X::integer(),Y::integer()}) -> bool() +%% @spec (This::wxRegion(), Pt::{X::integer(), Y::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregionoffset">external documentation</a>. offset(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -224,7 +224,7 @@ offset(#wx_ref{type=ThisT,ref=ThisRef},X,Y) %% union(This::wxRegion(), Region::wxRegion() | wxBitmap:wxBitmap()) -> bool() </c> %% </p> %% <p><c> -%% union(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c> +%% union(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c> %% </p> union(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) -> ?CLASS(ThisT,wxRegion), @@ -276,7 +276,7 @@ union(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H) %% 'Xor'(This::wxRegion(), Region::wxRegion()) -> bool() </c> %% </p> %% <p><c> -%% 'Xor'(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c> +%% 'Xor'(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c> %% </p> 'Xor'(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) -> ?CLASS(ThisT,wxRegion), diff --git a/lib/wx/src/gen/wxSashEvent.erl b/lib/wx/src/gen/wxSashEvent.erl index 480e241807..f9c58a04b1 100644 --- a/lib/wx/src/gen/wxSashEvent.erl +++ b/lib/wx/src/gen/wxSashEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -54,7 +54,7 @@ getEdge(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxSashEvent_GetEdge, <<ThisRef:32/?UI>>). -%% @spec (This::wxSashEvent()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxSashEvent()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashevent.html#wxsasheventgetdragrect">external documentation</a>. getDragRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSashEvent), diff --git a/lib/wx/src/gen/wxSashLayoutWindow.erl b/lib/wx/src/gen/wxSashLayoutWindow.erl index 9bc5a185ba..eb8eb38011 100644 --- a/lib/wx/src/gen/wxSashLayoutWindow.erl +++ b/lib/wx/src/gen/wxSashLayoutWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSashLayoutWindow() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowwxsashlayoutwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -114,7 +114,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxSashLayoutWindow(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -157,7 +157,7 @@ setAlignment(#wx_ref{type=ThisT,ref=ThisRef},Align) wxe_util:cast(?wxSashLayoutWindow_SetAlignment, <<ThisRef:32/?UI,Align:32/?UI>>). -%% @spec (This::wxSashLayoutWindow(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxSashLayoutWindow(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowsetdefaultsize">external documentation</a>. setDefaultSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxSashWindow.erl b/lib/wx/src/gen/wxSashWindow.erl index 49fb82f828..698cfb8fb6 100644 --- a/lib/wx/src/gen/wxSashWindow.erl +++ b/lib/wx/src/gen/wxSashWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSashWindow() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashwindow.html#wxsashwindowwxsashwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxScrollBar.erl b/lib/wx/src/gen/wxScrollBar.erl index 41ca8d867f..5c7890009f 100644 --- a/lib/wx/src/gen/wxScrollBar.erl +++ b/lib/wx/src/gen/wxScrollBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxScrollBar() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrollbar.html#wxscrollbarwxscrollbar">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -110,7 +110,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxScrollBar(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrollbar.html#wxscrollbarcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxScrolledWindow.erl b/lib/wx/src/gen/wxScrolledWindow.erl index a6f813d1a2..0693a79760 100644 --- a/lib/wx/src/gen/wxScrolledWindow.erl +++ b/lib/wx/src/gen/wxScrolledWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxScrolledWindow() -%% Option = {winid, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {winid, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowwxscrolledwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -105,7 +105,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options) wxe_util:construct(?wxScrolledWindow_new_2, <<ParentRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxScrolledWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()} +%% @spec (This::wxScrolledWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcscrolledposition">external documentation</a>. calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -113,7 +113,7 @@ calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:call(?wxScrolledWindow_CalcScrolledPosition_1, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(),Yy::integer()} +%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(), Yy::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcscrolledposition">external documentation</a>. calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) when is_integer(X),is_integer(Y) -> @@ -121,7 +121,7 @@ calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:call(?wxScrolledWindow_CalcScrolledPosition_4, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxScrolledWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()} +%% @spec (This::wxScrolledWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcunscrolledposition">external documentation</a>. calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -129,7 +129,7 @@ calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:call(?wxScrolledWindow_CalcUnscrolledPosition_1, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(),Yy::integer()} +%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(), Yy::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcunscrolledposition">external documentation</a>. calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) when is_integer(X),is_integer(Y) -> @@ -145,14 +145,14 @@ enableScrolling(#wx_ref{type=ThisT,ref=ThisRef},X_scrolling,Y_scrolling) wxe_util:cast(?wxScrolledWindow_EnableScrolling, <<ThisRef:32/?UI,(wxe_util:from_bool(X_scrolling)):32/?UI,(wxe_util:from_bool(Y_scrolling)):32/?UI>>). -%% @spec (This::wxScrolledWindow()) -> {PixelsPerUnitX::integer(),PixelsPerUnitY::integer()} +%% @spec (This::wxScrolledWindow()) -> {PixelsPerUnitX::integer(), PixelsPerUnitY::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowgetscrollpixelsperunit">external documentation</a>. getScrollPixelsPerUnit(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxScrolledWindow), wxe_util:call(?wxScrolledWindow_GetScrollPixelsPerUnit, <<ThisRef:32/?UI>>). -%% @spec (This::wxScrolledWindow()) -> {X::integer(),Y::integer()} +%% @spec (This::wxScrolledWindow()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowgetviewstart">external documentation</a>. getViewStart(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxScrolledWindow), diff --git a/lib/wx/src/gen/wxSingleChoiceDialog.erl b/lib/wx/src/gen/wxSingleChoiceDialog.erl index 16e0c3d8ce..e2b835917e 100644 --- a/lib/wx/src/gen/wxSingleChoiceDialog.erl +++ b/lib/wx/src/gen/wxSingleChoiceDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -97,7 +97,7 @@ new(Parent,Message,Caption,Choices) new(Parent,Message,Caption,Choices, []). %% @spec (Parent::wxWindow:wxWindow(), Message::string(), Caption::string(), Choices::[[string()]], [Option]) -> wxSingleChoiceDialog() -%% Option = {style, integer()} | {pos, {X::integer(),Y::integer()}} +%% Option = {style, integer()} | {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsinglechoicedialog.html#wxsinglechoicedialogwxsinglechoicedialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options) when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) -> diff --git a/lib/wx/src/gen/wxSizeEvent.erl b/lib/wx/src/gen/wxSizeEvent.erl index 9e7619ebbd..0898f4aed9 100644 --- a/lib/wx/src/gen/wxSizeEvent.erl +++ b/lib/wx/src/gen/wxSizeEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,7 +41,7 @@ parent_class(wxEvent) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -%% @spec (This::wxSizeEvent()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizeEvent()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeevent.html#wxsizeeventgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizeEvent), diff --git a/lib/wx/src/gen/wxSizer.erl b/lib/wx/src/gen/wxSizer.erl index e9b83a7333..0f1a92f379 100644 --- a/lib/wx/src/gen/wxSizer.erl +++ b/lib/wx/src/gen/wxSizer.erl @@ -132,7 +132,7 @@ addStretchSpacer(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxSizer_AddStretchSpacer, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxSizer()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizercalcmin">external documentation</a>. calcMin(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizer), @@ -182,7 +182,7 @@ detach(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) -> wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI>>). -%% @spec (This::wxSizer(), Window::wxWindow:wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizer(), Window::wxWindow:wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizerfit">external documentation</a>. fit(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) -> ?CLASS(ThisT,wxSizer), @@ -241,21 +241,21 @@ getItem(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Opt wxe_util:call(WindowOP, <<ThisRef:32/?UI,WindowRef:32/?UI, BinOpt/binary>>). -%% @spec (This::wxSizer()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizer), wxe_util:call(?wxSizer_GetSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizer()) -> {X::integer(),Y::integer()} +%% @spec (This::wxSizer()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizer), wxe_util:call(?wxSizer_GetPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizer()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizer()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetminsize">external documentation</a>. getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizer), @@ -596,7 +596,7 @@ setDimension(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Width,Height) wxe_util:cast(?wxSizer_SetDimension, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,Width:32/?UI,Height:32/?UI>>). -%% @spec (This::wxSizer(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxSizer(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizersetminsize">external documentation</a>. setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -612,14 +612,14 @@ setMinSize(#wx_ref{type=ThisT,ref=ThisRef},Width,Height) wxe_util:cast(?wxSizer_SetMinSize_2, <<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI>>). -%% @spec (This::wxSizer(),X::integer()|term(),Size::{W::integer(),H::integer()}) -> bool() +%% @spec (This::wxSizer(),X::integer()|term(),Size::{W::integer(), H::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizersetitemminsize">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% setItemMinSize(This::wxSizer(), Index::integer(), Size::{W::integer(),H::integer()}) -> bool() </c> +%% setItemMinSize(This::wxSizer(), Index::integer(), Size::{W::integer(), H::integer()}) -> bool() </c> %% </p> %% <p><c> -%% setItemMinSize(This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Size::{W::integer(),H::integer()}) -> bool() </c> +%% setItemMinSize(This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Size::{W::integer(), H::integer()}) -> bool() </c> %% </p> setItemMinSize(#wx_ref{type=ThisT,ref=ThisRef},Index,{SizeW,SizeH}) when is_integer(Index),is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxSizerItem.erl b/lib/wx/src/gen/wxSizerItem.erl index 1e9f05d53c..41cb86eae2 100644 --- a/lib/wx/src/gen/wxSizerItem.erl +++ b/lib/wx/src/gen/wxSizerItem.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Width,Height,Proportion,Flag,Border,#wx_ref{type=UserDataT,ref=UserDataRef}) wxe_util:construct(?wxSizerItem_new_6, <<Width:32/?UI,Height:32/?UI,Proportion:32/?UI,Flag:32/?UI,Border:32/?UI,UserDataRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemcalcmin">external documentation</a>. calcMin(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), @@ -124,14 +124,14 @@ getFlag(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxSizerItem_GetFlag, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetminsize">external documentation</a>. getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), wxe_util:call(?wxSizerItem_GetMinSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {X::integer(),Y::integer()} +%% @spec (This::wxSizerItem()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), @@ -152,14 +152,14 @@ getRatio(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxSizerItem_GetRatio, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxSizerItem()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetrect">external documentation</a>. getRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), wxe_util:call(?wxSizerItem_GetRect, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), @@ -173,7 +173,7 @@ getSizer(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxSizerItem_GetSizer, <<ThisRef:32/?UI>>). -%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()} +%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetspacer">external documentation</a>. getSpacer(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), @@ -230,7 +230,7 @@ setBorder(#wx_ref{type=ThisT,ref=ThisRef},Border) wxe_util:cast(?wxSizerItem_SetBorder, <<ThisRef:32/?UI,Border:32/?UI>>). -%% @spec (This::wxSizerItem(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxSizerItem(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetdimension">external documentation</a>. setDimension(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY},{SizeW,SizeH}) when is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH) -> @@ -254,7 +254,7 @@ setInitSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:cast(?wxSizerItem_SetInitSize, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetminsize">external documentation</a>. setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -285,7 +285,7 @@ setProportion(#wx_ref{type=ThisT,ref=ThisRef},Proportion) %% setRatio(This::wxSizerItem(), Ratio::float()) -> ok </c> %% </p> %% <p><c> -%% setRatio(This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok </c> +%% setRatio(This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok </c> %% </p> setRatio(#wx_ref{type=ThisT,ref=ThisRef},Ratio) when is_float(Ratio) -> @@ -314,7 +314,7 @@ setSizer(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=SizerT,ref=SizerRef}) -> wxe_util:cast(?wxSizerItem_SetSizer, <<ThisRef:32/?UI,SizerRef:32/?UI>>). -%% @spec (This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetspacer">external documentation</a>. setSpacer(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxSlider.erl b/lib/wx/src/gen/wxSlider.erl index c70f127a5b..c7a3d6f5c0 100644 --- a/lib/wx/src/gen/wxSlider.erl +++ b/lib/wx/src/gen/wxSlider.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -90,7 +90,7 @@ new(Parent,Id,Value,MinValue,MaxValue) new(Parent,Id,Value,MinValue,MaxValue, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Value::integer(), MinValue::integer(), MaxValue::integer(), [Option]) -> wxSlider() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxslider.html#wxsliderwxslider">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options) when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) -> @@ -111,7 +111,7 @@ create(This,Parent,Id,Value,MinValue,MaxValue) create(This,Parent,Id,Value,MinValue,MaxValue, []). %% @spec (This::wxSlider(), Parent::wxWindow:wxWindow(), Id::integer(), Value::integer(), MinValue::integer(), MaxValue::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxslider.html#wxslidercreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options) when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) -> diff --git a/lib/wx/src/gen/wxSpinButton.erl b/lib/wx/src/gen/wxSpinButton.erl index 027699e295..e269dbe329 100644 --- a/lib/wx/src/gen/wxSpinButton.erl +++ b/lib/wx/src/gen/wxSpinButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSpinButton() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinbutton.html#wxspinbuttonwxspinbutton">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -110,7 +110,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxSpinButton(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinbutton.html#wxspinbuttoncreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxSpinCtrl.erl b/lib/wx/src/gen/wxSpinCtrl.erl index 6b77376b40..c6e8ad2238 100644 --- a/lib/wx/src/gen/wxSpinCtrl.erl +++ b/lib/wx/src/gen/wxSpinCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSpinCtrl() -%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()} +%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinctrl.html#wxspinctrlwxspinctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -114,7 +114,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxSpinCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()} +%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinctrl.html#wxspinctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxSplashScreen.erl b/lib/wx/src/gen/wxSplashScreen.erl index 8806d07018..79ef8e413a 100644 --- a/lib/wx/src/gen/wxSplashScreen.erl +++ b/lib/wx/src/gen/wxSplashScreen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -100,7 +100,7 @@ new(Bitmap,SplashStyle,Milliseconds,Parent,Id) new(Bitmap,SplashStyle,Milliseconds,Parent,Id, []). %% @spec (Bitmap::wxBitmap:wxBitmap(), SplashStyle::integer(), Milliseconds::integer(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxSplashScreen() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplashscreen.html#wxsplashscreenwxsplashscreen">external documentation</a>. new(#wx_ref{type=BitmapT,ref=BitmapRef},SplashStyle,Milliseconds,#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(SplashStyle),is_integer(Milliseconds),is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxSplitterWindow.erl b/lib/wx/src/gen/wxSplitterWindow.erl index 9e27be7475..b17fed3151 100644 --- a/lib/wx/src/gen/wxSplitterWindow.erl +++ b/lib/wx/src/gen/wxSplitterWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSplitterWindow() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplitterwindow.html#wxsplitterwindowwxsplitterwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -112,7 +112,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxSplitterWindow(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplitterwindow.html#wxsplitterwindowcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxStaticBitmap.erl b/lib/wx/src/gen/wxStaticBitmap.erl index 6fbc59236d..31e39b3a6c 100644 --- a/lib/wx/src/gen/wxStaticBitmap.erl +++ b/lib/wx/src/gen/wxStaticBitmap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::wxBitmap:wxBitmap(), [Option]) -> wxStaticBitmap() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbitmap.html#wxstaticbitmapwxstaticbitmap">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=LabelT,ref=LabelRef}, Options) when is_integer(Id),is_list(Options) -> @@ -109,7 +109,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxStaticBitmap(), Parent::wxWindow:wxWindow(), Id::integer(), Label::wxBitmap:wxBitmap(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbitmap.html#wxstaticbitmapcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=LabelT,ref=LabelRef}, Options) when is_integer(Id),is_list(Options) -> diff --git a/lib/wx/src/gen/wxStaticBox.erl b/lib/wx/src/gen/wxStaticBox.erl index ad54184867..ec83ff5fd9 100644 --- a/lib/wx/src/gen/wxStaticBox.erl +++ b/lib/wx/src/gen/wxStaticBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxStaticBox() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbox.html#wxstaticboxwxstaticbox">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> @@ -109,7 +109,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxStaticBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbox.html#wxstaticboxcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> diff --git a/lib/wx/src/gen/wxStaticLine.erl b/lib/wx/src/gen/wxStaticLine.erl index e3a1bedbdc..a850065ba0 100644 --- a/lib/wx/src/gen/wxStaticLine.erl +++ b/lib/wx/src/gen/wxStaticLine.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxStaticLine() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticline.html#wxstaticlinewxstaticline">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -110,7 +110,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxStaticLine(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticline.html#wxstaticlinecreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> diff --git a/lib/wx/src/gen/wxStaticText.erl b/lib/wx/src/gen/wxStaticText.erl index 46c73a5998..301999d49a 100644 --- a/lib/wx/src/gen/wxStaticText.erl +++ b/lib/wx/src/gen/wxStaticText.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxStaticText() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatictext.html#wxstatictextwxstatictext">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> @@ -109,7 +109,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxStaticText(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatictext.html#wxstatictextcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> diff --git a/lib/wx/src/gen/wxStatusBar.erl b/lib/wx/src/gen/wxStatusBar.erl index 52467117d7..6e77761f1d 100644 --- a/lib/wx/src/gen/wxStatusBar.erl +++ b/lib/wx/src/gen/wxStatusBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -121,7 +121,7 @@ create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Opti wxe_util:call(?wxStatusBar_Create, <<ThisRef:32/?UI,ParentRef:32/?UI, BinOpt/binary>>). -%% @spec (This::wxStatusBar(), I::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() +%% @spec (This::wxStatusBar(), I::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatusbar.html#wxstatusbargetfieldrect">external documentation</a>. getFieldRect(#wx_ref{type=ThisT,ref=ThisRef},I,{RectX,RectY,RectW,RectH}) when is_integer(I),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl index 71d1bd0d53..61f0e5afef 100644 --- a/lib/wx/src/gen/wxStyledTextCtrl.erl +++ b/lib/wx/src/gen/wxStyledTextCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -190,7 +190,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxStyledTextCtrl() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlwxstyledtextctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -211,7 +211,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxStyledTextCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -385,7 +385,7 @@ setViewWhiteSpace(#wx_ref{type=ThisT,ref=ThisRef},ViewWS) wxe_util:cast(?wxStyledTextCtrl_SetViewWhiteSpace, <<ThisRef:32/?UI,ViewWS:32/?UI>>). -%% @spec (This::wxStyledTextCtrl(), Pt::{X::integer(),Y::integer()}) -> integer() +%% @spec (This::wxStyledTextCtrl(), Pt::{X::integer(), Y::integer()}) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlpositionfrompoint">external documentation</a>. positionFromPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -425,7 +425,7 @@ setAnchor(#wx_ref{type=ThisT,ref=ThisRef},PosAnchor) wxe_util:cast(?wxStyledTextCtrl_SetAnchor, <<ThisRef:32/?UI,PosAnchor:32/?UI>>). -%% @spec (This::wxStyledTextCtrl()) -> {string(),LinePos::integer()} +%% @spec (This::wxStyledTextCtrl()) -> {string(), LinePos::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetcurline">external documentation</a>. getCurLine(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxStyledTextCtrl), @@ -1454,7 +1454,7 @@ findText(#wx_ref{type=ThisT,ref=ThisRef},MinPos,MaxPos,Text, Options) wxe_util:call(?wxStyledTextCtrl_FindText, <<ThisRef:32/?UI,MinPos:32/?UI,MaxPos:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>). -%% @spec (This::wxStyledTextCtrl(), DoDraw::bool(), StartPos::integer(), EndPos::integer(), Draw::wxDC:wxDC(), Target::wxDC:wxDC(), RenderRect::{X::integer(),Y::integer(),W::integer(),H::integer()}, PageRect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> integer() +%% @spec (This::wxStyledTextCtrl(), DoDraw::bool(), StartPos::integer(), EndPos::integer(), Draw::wxDC:wxDC(), Target::wxDC:wxDC(), RenderRect::{X::integer(), Y::integer(), W::integer(), H::integer()}, PageRect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlformatrange">external documentation</a>. formatRange(#wx_ref{type=ThisT,ref=ThisRef},DoDraw,StartPos,EndPos,#wx_ref{type=DrawT,ref=DrawRef},#wx_ref{type=TargetT,ref=TargetRef},{RenderRectX,RenderRectY,RenderRectW,RenderRectH},{PageRectX,PageRectY,PageRectW,PageRectH}) when is_boolean(DoDraw),is_integer(StartPos),is_integer(EndPos),is_integer(RenderRectX),is_integer(RenderRectY),is_integer(RenderRectW),is_integer(RenderRectH),is_integer(PageRectX),is_integer(PageRectY),is_integer(PageRectW),is_integer(PageRectH) -> @@ -3417,14 +3417,14 @@ setMargins(#wx_ref{type=ThisT,ref=ThisRef},Left,Right) wxe_util:cast(?wxStyledTextCtrl_SetMargins, <<ThisRef:32/?UI,Left:32/?UI,Right:32/?UI>>). -%% @spec (This::wxStyledTextCtrl()) -> {StartPos::integer(),EndPos::integer()} +%% @spec (This::wxStyledTextCtrl()) -> {StartPos::integer(), EndPos::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetselection">external documentation</a>. getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxStyledTextCtrl), wxe_util:call(?wxStyledTextCtrl_GetSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxStyledTextCtrl(), Pos::integer()) -> {X::integer(),Y::integer()} +%% @spec (This::wxStyledTextCtrl(), Pos::integer()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlpointfromposition">external documentation</a>. pointFromPosition(#wx_ref{type=ThisT,ref=ThisRef},Pos) when is_integer(Pos) -> @@ -3562,7 +3562,7 @@ insertTextRaw(#wx_ref{type=ThisT,ref=ThisRef},Pos,Text) wxe_util:cast(?wxStyledTextCtrl_InsertTextRaw, <<ThisRef:32/?UI,Pos:32/?UI>>). -%% @spec (This::wxStyledTextCtrl()) -> {binary(),LinePos::integer()} +%% @spec (This::wxStyledTextCtrl()) -> {binary(), LinePos::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetcurlineraw">external documentation</a>. getCurLineRaw(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxStyledTextCtrl), diff --git a/lib/wx/src/gen/wxSystemOptions.erl b/lib/wx/src/gen/wxSystemOptions.erl new file mode 100644 index 0000000000..d5e504632b --- /dev/null +++ b/lib/wx/src/gen/wxSystemOptions.erl @@ -0,0 +1,87 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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 online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html">wxSystemOptions</a>. +%% @type wxSystemOptions(). An object reference, The representation is internal +%% and can be changed without notice. It can't be used for comparsion +%% stored on disc or distributed for use on other nodes. + +-module(wxSystemOptions). +-include("wxe.hrl"). +-export([getOption/1,getOptionInt/1,hasOption/1,isFalse/1,setOption/2]). + +%% inherited exports +-export([parent_class/1]). + +%% @hidden +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +%% @spec (Name::string()) -> string() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsgetoption">external documentation</a>. +getOption(Name) + when is_list(Name) -> + Name_UC = unicode:characters_to_binary([Name,0]), + wxe_util:call(?wxSystemOptions_GetOption, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>). + +%% @spec (Name::string()) -> integer() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsgetoptionint">external documentation</a>. +getOptionInt(Name) + when is_list(Name) -> + Name_UC = unicode:characters_to_binary([Name,0]), + wxe_util:call(?wxSystemOptions_GetOptionInt, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>). + +%% @spec (Name::string()) -> bool() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionshasoption">external documentation</a>. +hasOption(Name) + when is_list(Name) -> + Name_UC = unicode:characters_to_binary([Name,0]), + wxe_util:call(?wxSystemOptions_HasOption, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>). + +%% @spec (Name::string()) -> bool() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsisfalse">external documentation</a>. +isFalse(Name) + when is_list(Name) -> + Name_UC = unicode:characters_to_binary([Name,0]), + wxe_util:call(?wxSystemOptions_IsFalse, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>). + +%% @spec (Name::string(),X::integer()|string()) -> ok +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionssetoption">external documentation</a>. +%% <br /> Alternatives: +%% <p><c> +%% setOption(Name::string(), Value::integer()) -> ok </c> +%% </p> +%% <p><c> +%% setOption(Name::string(), Value::string()) -> ok </c> +%% </p> +setOption(Name,Value) + when is_list(Name),is_integer(Value) -> + Name_UC = unicode:characters_to_binary([Name,0]), + wxe_util:cast(?wxSystemOptions_SetOption_2_0, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,Value:32/?UI>>); +setOption(Name,Value) + when is_list(Name),is_list(Value) -> + Name_UC = unicode:characters_to_binary([Name,0]), + Value_UC = unicode:characters_to_binary([Value,0]), + wxe_util:cast(?wxSystemOptions_SetOption_2_1, + <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(Value_UC)):32/?UI,(Value_UC)/binary, 0:(((8- ((4+byte_size(Value_UC)) band 16#7)) band 16#7))/unit:8>>). + diff --git a/lib/wx/src/gen/wxTextCtrl.erl b/lib/wx/src/gen/wxTextCtrl.erl index b4af23bdd9..b32f45b83b 100644 --- a/lib/wx/src/gen/wxTextCtrl.erl +++ b/lib/wx/src/gen/wxTextCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -96,7 +96,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxTextCtrl() -%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlwxtextctrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -176,7 +176,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxTextCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -266,7 +266,7 @@ getRange(#wx_ref{type=ThisT,ref=ThisRef},From,To) wxe_util:call(?wxTextCtrl_GetRange, <<ThisRef:32/?UI,From:32/?UI,To:32/?UI>>). -%% @spec (This::wxTextCtrl()) -> {From::integer(),To::integer()} +%% @spec (This::wxTextCtrl()) -> {From::integer(), To::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlgetselection">external documentation</a>. getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxTextCtrl), @@ -357,7 +357,7 @@ paste(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxTextCtrl_Paste, <<ThisRef:32/?UI>>). -%% @spec (This::wxTextCtrl(), Pos::integer()) -> {bool(),X::integer(),Y::integer()} +%% @spec (This::wxTextCtrl(), Pos::integer()) -> {bool(), X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlpositiontoxy">external documentation</a>. positionToXY(#wx_ref{type=ThisT,ref=ThisRef},Pos) when is_integer(Pos) -> diff --git a/lib/wx/src/gen/wxTextEntryDialog.erl b/lib/wx/src/gen/wxTextEntryDialog.erl index a30c32dd53..53694a47e6 100644 --- a/lib/wx/src/gen/wxTextEntryDialog.erl +++ b/lib/wx/src/gen/wxTextEntryDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,7 @@ new(Parent,Message) new(Parent,Message, []). %% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxTextEntryDialog() -%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} +%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextentrydialog.html#wxtextentrydialogwxtextentrydialog">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options) when is_list(Message),is_list(Options) -> diff --git a/lib/wx/src/gen/wxToggleButton.erl b/lib/wx/src/gen/wxToggleButton.erl index ab595c1906..d7755cc50b 100644 --- a/lib/wx/src/gen/wxToggleButton.erl +++ b/lib/wx/src/gen/wxToggleButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -88,7 +88,7 @@ new(Parent,Id,Label) new(Parent,Id,Label, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxToggleButton() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtogglebutton.html#wxtogglebuttonwxtogglebutton">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> @@ -110,7 +110,7 @@ create(This,Parent,Id,Label) create(This,Parent,Id,Label, []). %% @spec (This::wxToggleButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtogglebutton.html#wxtogglebuttoncreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> diff --git a/lib/wx/src/gen/wxToolBar.erl b/lib/wx/src/gen/wxToolBar.erl index c68936d493..59369368f0 100644 --- a/lib/wx/src/gen/wxToolBar.erl +++ b/lib/wx/src/gen/wxToolBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -327,21 +327,21 @@ findToolForPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:call(?wxToolBar_FindToolForPosition, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()} +%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargettoolsize">external documentation</a>. getToolSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxToolBar), wxe_util:call(?wxToolBar_GetToolSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()} +%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargettoolbitmapsize">external documentation</a>. getToolBitmapSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxToolBar), wxe_util:call(?wxToolBar_GetToolBitmapSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()} +%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargetmargins">external documentation</a>. getMargins(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxToolBar), @@ -504,7 +504,7 @@ setMargins(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:cast(?wxToolBar_SetMargins, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxToolBar(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxToolBar(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarsettoolbitmapsize">external documentation</a>. setToolBitmapSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxToolbook.erl b/lib/wx/src/gen/wxToolbook.erl index 4d188e979d..764f66c2e5 100644 --- a/lib/wx/src/gen/wxToolbook.erl +++ b/lib/wx/src/gen/wxToolbook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxToolbook() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookwxtoolbook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -160,7 +160,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxToolbook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxToolbook_GetSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxToolbook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxToolbook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi wxe_util:cast(?wxToolbook_SetImageList, <<ThisRef:32/?UI,ImageListRef:32/?UI>>). -%% @spec (This::wxToolbook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxToolbook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbooksetpagesize">external documentation</a>. setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl index e3fe4c9612..77705ec76e 100644 --- a/lib/wx/src/gen/wxTreeCtrl.erl +++ b/lib/wx/src/gen/wxTreeCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -108,7 +108,7 @@ new(Parent) new(Parent, []). %% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxTreeCtrl() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlwxtreectrl">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -204,7 +204,7 @@ create(This,Parent) create(This,Parent, []). %% @spec (This::wxTreeCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()} +%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> @@ -267,13 +267,13 @@ expand(#wx_ref{type=ThisT,ref=ThisRef},Item) wxe_util:cast(?wxTreeCtrl_Expand, <<ThisRef:32/?UI,0:32,Item:64/?UI>>). -%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() +%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() %% @equiv getBoundingRect(This,Item,Rect, []) getBoundingRect(This,Item,Rect={RectX,RectY,RectW,RectH}) when is_record(This, wx_ref),is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> getBoundingRect(This,Item,Rect, []). -%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> bool() +%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> bool() %% Option = {textOnly, bool()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetboundingrect">external documentation</a>. getBoundingRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Options) @@ -317,7 +317,7 @@ getEditControl(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxTreeCtrl_GetEditControl, <<ThisRef:32/?UI>>). -%% @spec (This::wxTreeCtrl(), Item::integer()) -> {integer(),Cookie::integer()} +%% @spec (This::wxTreeCtrl(), Item::integer()) -> {integer(), Cookie::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetfirstchild">external documentation</a>. getFirstChild(#wx_ref{type=ThisT,ref=ThisRef},Item) when is_integer(Item) -> @@ -325,7 +325,7 @@ getFirstChild(#wx_ref{type=ThisT,ref=ThisRef},Item) wxe_util:call(?wxTreeCtrl_GetFirstChild, <<ThisRef:32/?UI,0:32,Item:64/?UI>>). -%% @spec (This::wxTreeCtrl(), Item::integer(), Cookie::integer()) -> {integer(),Cookie::integer()} +%% @spec (This::wxTreeCtrl(), Item::integer(), Cookie::integer()) -> {integer(), Cookie::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetnextchild">external documentation</a>. getNextChild(#wx_ref{type=ThisT,ref=ThisRef},Item,Cookie) when is_integer(Item),is_integer(Cookie) -> @@ -478,7 +478,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxTreeCtrl_GetSelection, <<ThisRef:32/?UI>>). -%% @spec (This::wxTreeCtrl()) -> {integer(),Val::[integer()]} +%% @spec (This::wxTreeCtrl()) -> {integer(), Val::[integer()]} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetselections">external documentation</a>. getSelections(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxTreeCtrl), @@ -492,7 +492,7 @@ getStateImageList(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxTreeCtrl_GetStateImageList, <<ThisRef:32/?UI>>). -%% @spec (This::wxTreeCtrl(), Point::{X::integer(),Y::integer()}) -> integer() +%% @spec (This::wxTreeCtrl(), Point::{X::integer(), Y::integer()}) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY}) when is_integer(PointX),is_integer(PointY) -> diff --git a/lib/wx/src/gen/wxTreeEvent.erl b/lib/wx/src/gen/wxTreeEvent.erl index d5379b7abe..0264d43568 100644 --- a/lib/wx/src/gen/wxTreeEvent.erl +++ b/lib/wx/src/gen/wxTreeEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -83,7 +83,7 @@ getOldItem(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxTreeEvent_GetOldItem, <<ThisRef:32/?UI>>). -%% @spec (This::wxTreeEvent()) -> {X::integer(),Y::integer()} +%% @spec (This::wxTreeEvent()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreeevent.html#wxtreeeventgetpoint">external documentation</a>. getPoint(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxTreeEvent), diff --git a/lib/wx/src/gen/wxTreebook.erl b/lib/wx/src/gen/wxTreebook.erl index a515ec9639..24f5d72c43 100644 --- a/lib/wx/src/gen/wxTreebook.erl +++ b/lib/wx/src/gen/wxTreebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -94,7 +94,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxTreebook() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookwxtreebook">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -161,7 +161,7 @@ create(This,Parent,Id) create(This,Parent,Id, []). %% @spec (This::wxTreebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookcreate">external documentation</a>. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -276,7 +276,7 @@ isNodeExpanded(#wx_ref{type=ThisT,ref=ThisRef},Pos) wxe_util:call(?wxTreebook_IsNodeExpanded, <<ThisRef:32/?UI,Pos:32/?UI>>). -%% @spec (This::wxTreebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()} +%% @spec (This::wxTreebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookhittest">external documentation</a>. hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -334,7 +334,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi wxe_util:cast(?wxTreebook_SetImageList, <<ThisRef:32/?UI,ImageListRef:32/?UI>>). -%% @spec (This::wxTreebook(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxTreebook(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebooksetpagesize">external documentation</a>. setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl index 031314bfe2..6b57cf508e 100644 --- a/lib/wx/src/gen/wxWindow.erl +++ b/lib/wx/src/gen/wxWindow.erl @@ -86,7 +86,7 @@ new(Parent,Id) new(Parent,Id, []). %% @spec (Parent::wxWindow(), Id::integer(), [Option]) -> wxWindow() -%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} +%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowwxwindow">external documentation</a>. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> @@ -99,7 +99,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) wxe_util:construct(?wxWindow_new_3, <<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>). -%% @spec (This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowcachebestsize">external documentation</a>. cacheBestSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -193,7 +193,7 @@ clearBackground(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxWindow_ClearBackground, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowclienttoscreen">external documentation</a>. clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -201,7 +201,7 @@ clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) wxe_util:call(?wxWindow_ClientToScreen_1, <<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>). -%% @spec (This::wxWindow(), X::integer(), Y::integer()) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow(), X::integer(), Y::integer()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowclienttoscreen">external documentation</a>. clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},X,Y) when is_integer(X),is_integer(Y) -> @@ -227,7 +227,7 @@ close(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:call(?wxWindow_Close, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxWindow(), Sz::{W::integer(),H::integer()}) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow(), Sz::{W::integer(), H::integer()}) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowconvertdialogtopixels">external documentation</a>. convertDialogToPixels(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH}) when is_integer(SzW),is_integer(SzH) -> @@ -235,7 +235,7 @@ convertDialogToPixels(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH}) wxe_util:call(?wxWindow_ConvertDialogToPixels, <<ThisRef:32/?UI,SzW:32/?UI,SzH:32/?UI>>). -%% @spec (This::wxWindow(), Sz::{W::integer(),H::integer()}) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow(), Sz::{W::integer(), H::integer()}) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowconvertpixelstodialog">external documentation</a>. convertPixelsToDialog(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH}) when is_integer(SzW),is_integer(SzH) -> @@ -406,7 +406,7 @@ getBackgroundStyle(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetBackgroundStyle, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetbestsize">external documentation</a>. getBestSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -447,7 +447,7 @@ getChildren(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetChildren, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetclientsize">external documentation</a>. getClientSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -538,14 +538,14 @@ getLabel(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetLabel, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetmaxsize">external documentation</a>. getMaxSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), wxe_util:call(?wxWindow_GetMaxSize, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetminsize">external documentation</a>. getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -566,28 +566,28 @@ getParent(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetParent, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetposition">external documentation</a>. getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), wxe_util:call(?wxWindow_GetPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetrect">external documentation</a>. getRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), wxe_util:call(?wxWindow_GetRect, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetscreenposition">external documentation</a>. getScreenPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), wxe_util:call(?wxWindow_GetScreenPosition, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {X::integer(),Y::integer(),W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {X::integer(), Y::integer(), W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetscreenrect">external documentation</a>. getScreenRect(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -618,7 +618,7 @@ getScrollThumb(#wx_ref{type=ThisT,ref=ThisRef},Orient) wxe_util:call(?wxWindow_GetScrollThumb, <<ThisRef:32/?UI,Orient:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetsize">external documentation</a>. getSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -632,13 +632,13 @@ getSizer(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetSizer, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow(), String::string()) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()} +%% @spec (This::wxWindow(), String::string()) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()} %% @equiv getTextExtent(This,String, []) getTextExtent(This,String) when is_record(This, wx_ref),is_list(String) -> getTextExtent(This,String, []). -%% @spec (This::wxWindow(), String::string(), [Option]) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()} +%% @spec (This::wxWindow(), String::string(), [Option]) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()} %% Option = {theFont, wxFont:wxFont()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgettextextent">external documentation</a>. getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options) @@ -665,7 +665,7 @@ getUpdateRegion(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxWindow_GetUpdateRegion, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {W::integer(),H::integer()} +%% @spec (This::wxWindow()) -> {W::integer(), H::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetvirtualsize">external documentation</a>. getVirtualSize(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -749,10 +749,10 @@ isEnabled(#wx_ref{type=ThisT,ref=ThisRef}) -> %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowisexposed">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% isExposed(This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> bool() </c> +%% isExposed(This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> bool() </c> %% </p> %% <p><c> -%% isExposed(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c> +%% isExposed(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c> %% </p> isExposed(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -848,7 +848,7 @@ makeModal(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:cast(?wxWindow_MakeModal, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> ok +%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> ok %% @equiv move(This,Pt, []) move(This,Pt={PtX,PtY}) when is_record(This, wx_ref),is_integer(PtX),is_integer(PtY) -> @@ -860,7 +860,7 @@ move(This,Pt={PtX,PtY}) %% <p><c> %% move(This::wxWindow(), X::integer(), Y::integer()) -> move(This,X,Y, []) </c></p> %% <p><c> -%% move(This::wxWindow(), Pt::{X::integer(),Y::integer()}, [Option]) -> ok </c> +%% move(This::wxWindow(), Pt::{X::integer(), Y::integer()}, [Option]) -> ok </c> %%<br /> Option = {flags, integer()} %% </p> @@ -961,7 +961,7 @@ popupMenu(This,Menu) popupMenu(This,Menu, []). %% @spec (This::wxWindow(), Menu::wxMenu:wxMenu(), [Option]) -> bool() -%% Option = {pos, {X::integer(),Y::integer()}} +%% Option = {pos, {X::integer(), Y::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowpopupmenu">external documentation</a>. popupMenu(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=MenuT,ref=MenuRef}, Options) when is_list(Options) -> @@ -996,7 +996,7 @@ refresh(This) refresh(This, []). %% @spec (This::wxWindow(), [Option]) -> ok -%% Option = {eraseBackground, bool()} | {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}} +%% Option = {eraseBackground, bool()} | {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowrefresh">external documentation</a>. refresh(#wx_ref{type=ThisT,ref=ThisRef}, Options) when is_list(Options) -> @@ -1008,13 +1008,13 @@ refresh(#wx_ref{type=ThisT,ref=ThisRef}, Options) wxe_util:cast(?wxWindow_Refresh, <<ThisRef:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %% @equiv refreshRect(This,Rect, []) refreshRect(This,Rect={RectX,RectY,RectW,RectH}) when is_record(This, wx_ref),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> refreshRect(This,Rect, []). -%% @spec (This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok +%% @spec (This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok %% Option = {eraseBackground, bool()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowrefreshrect">external documentation</a>. refreshRect(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}, Options) @@ -1049,14 +1049,14 @@ reparent(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=NewParentT,ref=NewParentRe wxe_util:call(?wxWindow_Reparent, <<ThisRef:32/?UI,NewParentRef:32/?UI>>). -%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscreentoclient">external documentation</a>. screenToClient(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), wxe_util:call(?wxWindow_ScreenToClient_2, <<ThisRef:32/?UI>>). -%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()} +%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscreentoclient">external documentation</a>. screenToClient(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> @@ -1087,7 +1087,7 @@ scrollWindow(This,Dx,Dy) scrollWindow(This,Dx,Dy, []). %% @spec (This::wxWindow(), Dx::integer(), Dy::integer(), [Option]) -> ok -%% Option = {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}} +%% Option = {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscrollwindow">external documentation</a>. scrollWindow(#wx_ref{type=ThisT,ref=ThisRef},Dx,Dy, Options) when is_integer(Dx),is_integer(Dy),is_list(Options) -> @@ -1184,7 +1184,7 @@ setCursor(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=CursorT,ref=CursorRef}) - wxe_util:call(?wxWindow_SetCursor, <<ThisRef:32/?UI,CursorRef:32/?UI>>). -%% @spec (This::wxWindow(), MaxSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), MaxSize::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetmaxsize">external documentation</a>. setMaxSize(#wx_ref{type=ThisT,ref=ThisRef},{MaxSizeW,MaxSizeH}) when is_integer(MaxSizeW),is_integer(MaxSizeH) -> @@ -1192,7 +1192,7 @@ setMaxSize(#wx_ref{type=ThisT,ref=ThisRef},{MaxSizeW,MaxSizeH}) wxe_util:cast(?wxWindow_SetMaxSize, <<ThisRef:32/?UI,MaxSizeW:32/?UI,MaxSizeH:32/?UI>>). -%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetminsize">external documentation</a>. setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{MinSizeW,MinSizeH}) when is_integer(MinSizeW),is_integer(MinSizeH) -> @@ -1353,9 +1353,9 @@ setScrollPos(#wx_ref{type=ThisT,ref=ThisRef},Orient,Pos, Options) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetsize">external documentation</a>. %% <br /> Alternatives: %% <p><c> -%% setSize(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> setSize(This,Rect, []) </c></p> +%% setSize(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> setSize(This,Rect, []) </c></p> %% <p><c> -%% setSize(This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok </c> +%% setSize(This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok </c> %% </p> setSize(This,Rect={RectX,RectY,RectW,RectH}) @@ -1374,7 +1374,7 @@ setSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) %% setSize(This::wxWindow(), Width::integer(), Height::integer()) -> ok </c> %% </p> %% <p><c> -%% setSize(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok </c> +%% setSize(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok </c> %%<br /> Option = {sizeFlags, integer()} %% </p> setSize(#wx_ref{type=ThisT,ref=ThisRef},Width,Height) @@ -1409,7 +1409,7 @@ setSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Width,Height, Options) wxe_util:cast(?wxWindow_SetSize_5, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>). -%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok %% @equiv setSizeHints(This,MinSize, []) setSizeHints(This,MinSize={MinSizeW,MinSizeH}) when is_record(This, wx_ref),is_integer(MinSizeW),is_integer(MinSizeH) -> @@ -1421,8 +1421,8 @@ setSizeHints(This,MinSize={MinSizeW,MinSizeH}) %% <p><c> %% setSizeHints(This::wxWindow(), MinW::integer(), MinH::integer()) -> setSizeHints(This,MinW,MinH, []) </c></p> %% <p><c> -%% setSizeHints(This::wxWindow(), MinSize::{W::integer(),H::integer()}, [Option]) -> ok </c> -%%<br /> Option = {maxSize, {W::integer(),H::integer()}} | {incSize, {W::integer(),H::integer()}} +%% setSizeHints(This::wxWindow(), MinSize::{W::integer(), H::integer()}, [Option]) -> ok </c> +%%<br /> Option = {maxSize, {W::integer(), H::integer()}} | {incSize, {W::integer(), H::integer()}} %% </p> setSizeHints(This,MinW,MinH) @@ -1520,7 +1520,7 @@ setToolTip(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=TipT,ref=TipRef}) -> wxe_util:cast(?wxWindow_SetToolTip_1_1, <<ThisRef:32/?UI,TipRef:32/?UI>>). -%% @spec (This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetvirtualsize">external documentation</a>. setVirtualSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> @@ -1536,7 +1536,7 @@ setVirtualSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:cast(?wxWindow_SetVirtualSize_2, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). -%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok +%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok %% @equiv setVirtualSizeHints(This,MinSize, []) setVirtualSizeHints(This,MinSize={MinSizeW,MinSizeH}) when is_record(This, wx_ref),is_integer(MinSizeW),is_integer(MinSizeH) -> @@ -1548,8 +1548,8 @@ setVirtualSizeHints(This,MinSize={MinSizeW,MinSizeH}) %% <p><c> %% setVirtualSizeHints(This::wxWindow(), MinW::integer(), MinH::integer()) -> setVirtualSizeHints(This,MinW,MinH, []) </c></p> %% <p><c> -%% setVirtualSizeHints(This::wxWindow(), MinSize::{W::integer(),H::integer()}, [Option]) -> ok </c> -%%<br /> Option = {maxSize, {W::integer(),H::integer()}} +%% setVirtualSizeHints(This::wxWindow(), MinSize::{W::integer(), H::integer()}, [Option]) -> ok </c> +%%<br /> Option = {maxSize, {W::integer(), H::integer()}} %% </p> setVirtualSizeHints(This,MinW,MinH) diff --git a/lib/wx/src/gen/wx_misc.erl b/lib/wx/src/gen/wx_misc.erl index cf23d4cf8b..3382d898e4 100644 --- a/lib/wx/src/gen/wx_misc.erl +++ b/lib/wx/src/gen/wx_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,7 +39,7 @@ getKeyState(Key) wxe_util:call(?utils_wxGetKeyState, <<Key:32/?UI>>). -%% @spec () -> {X::integer(),Y::integer()} +%% @spec () -> {X::integer(), Y::integer()} %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxgetmouseposition">external documentation</a>. getMousePosition() -> wxe_util:call(?utils_wxGetMousePosition, @@ -74,14 +74,14 @@ findMenuItemId(#wx_ref{type=FrameT,ref=FrameRef},MenuString,ItemString) wxe_util:call(?utils_wxFindMenuItemId, <<FrameRef:32/?UI,(byte_size(MenuString_UC)):32/?UI,(MenuString_UC)/binary, 0:(((8- ((0+byte_size(MenuString_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(ItemString_UC)):32/?UI,(ItemString_UC)/binary, 0:(((8- ((4+byte_size(ItemString_UC)) band 16#7)) band 16#7))/unit:8>>). -%% @spec (Pt::{X::integer(),Y::integer()}) -> wxWindow:wxWindow() +%% @spec (Pt::{X::integer(), Y::integer()}) -> wxWindow:wxWindow() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxgenericfindwindowatpoint">external documentation</a>. genericFindWindowAtPoint({PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> wxe_util:call(?utils_wxGenericFindWindowAtPoint, <<PtX:32/?UI,PtY:32/?UI>>). -%% @spec (Pt::{X::integer(),Y::integer()}) -> wxWindow:wxWindow() +%% @spec (Pt::{X::integer(), Y::integer()}) -> wxWindow:wxWindow() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxfindwindowatpoint">external documentation</a>. findWindowAtPoint({PtX,PtY}) when is_integer(PtX),is_integer(PtY) -> diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl index 960f67a1f6..4224c54200 100644 --- a/lib/wx/src/gen/wxe_debug.hrl +++ b/lib/wx/src/gen/wxe_debug.hrl @@ -3273,26 +3273,32 @@ wxdebug_table() -> {3489, {wxSystemSettings, getFont, 1}}, {3490, {wxSystemSettings, getMetric, 2}}, {3491, {wxSystemSettings, getScreenType, 0}}, - {3492, {wxAuiNotebookEvent, setSelection, 1}}, - {3493, {wxAuiNotebookEvent, getSelection, 0}}, - {3494, {wxAuiNotebookEvent, setOldSelection, 1}}, - {3495, {wxAuiNotebookEvent, getOldSelection, 0}}, - {3496, {wxAuiNotebookEvent, setDragSource, 1}}, - {3497, {wxAuiNotebookEvent, getDragSource, 0}}, - {3498, {wxAuiManagerEvent, setManager, 1}}, - {3499, {wxAuiManagerEvent, getManager, 0}}, - {3500, {wxAuiManagerEvent, setPane, 1}}, - {3501, {wxAuiManagerEvent, getPane, 0}}, - {3502, {wxAuiManagerEvent, setButton, 1}}, - {3503, {wxAuiManagerEvent, getButton, 0}}, - {3504, {wxAuiManagerEvent, setDC, 1}}, - {3505, {wxAuiManagerEvent, getDC, 0}}, - {3506, {wxAuiManagerEvent, veto, 1}}, - {3507, {wxAuiManagerEvent, getVeto, 0}}, - {3508, {wxAuiManagerEvent, setCanVeto, 1}}, - {3509, {wxAuiManagerEvent, canVeto, 0}}, - {3510, {wxLogNull, new, 0}}, - {3511, {wxLogNull, 'Destroy', undefined}}, + {3492, {wxSystemOptions, getOption, 1}}, + {3493, {wxSystemOptions, getOptionInt, 1}}, + {3494, {wxSystemOptions, hasOption, 1}}, + {3495, {wxSystemOptions, isFalse, 1}}, + {3496, {wxSystemOptions, setOption_2_1, 2}}, + {3497, {wxSystemOptions, setOption_2_0, 2}}, + {3498, {wxAuiNotebookEvent, setSelection, 1}}, + {3499, {wxAuiNotebookEvent, getSelection, 0}}, + {3500, {wxAuiNotebookEvent, setOldSelection, 1}}, + {3501, {wxAuiNotebookEvent, getOldSelection, 0}}, + {3502, {wxAuiNotebookEvent, setDragSource, 1}}, + {3503, {wxAuiNotebookEvent, getDragSource, 0}}, + {3504, {wxAuiManagerEvent, setManager, 1}}, + {3505, {wxAuiManagerEvent, getManager, 0}}, + {3506, {wxAuiManagerEvent, setPane, 1}}, + {3507, {wxAuiManagerEvent, getPane, 0}}, + {3508, {wxAuiManagerEvent, setButton, 1}}, + {3509, {wxAuiManagerEvent, getButton, 0}}, + {3510, {wxAuiManagerEvent, setDC, 1}}, + {3511, {wxAuiManagerEvent, getDC, 0}}, + {3512, {wxAuiManagerEvent, veto, 1}}, + {3513, {wxAuiManagerEvent, getVeto, 0}}, + {3514, {wxAuiManagerEvent, setCanVeto, 1}}, + {3515, {wxAuiManagerEvent, canVeto, 0}}, + {3516, {wxLogNull, new, 0}}, + {3517, {wxLogNull, 'Destroy', undefined}}, {-1, {mod, func, -1}} ]. diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl index af74caaa25..55cbee5572 100644 --- a/lib/wx/src/gen/wxe_funcs.hrl +++ b/lib/wx/src/gen/wxe_funcs.hrl @@ -3270,23 +3270,29 @@ -define(wxSystemSettings_GetFont, 3489). -define(wxSystemSettings_GetMetric, 3490). -define(wxSystemSettings_GetScreenType, 3491). --define(wxAuiNotebookEvent_SetSelection, 3492). --define(wxAuiNotebookEvent_GetSelection, 3493). --define(wxAuiNotebookEvent_SetOldSelection, 3494). --define(wxAuiNotebookEvent_GetOldSelection, 3495). --define(wxAuiNotebookEvent_SetDragSource, 3496). --define(wxAuiNotebookEvent_GetDragSource, 3497). --define(wxAuiManagerEvent_SetManager, 3498). --define(wxAuiManagerEvent_GetManager, 3499). --define(wxAuiManagerEvent_SetPane, 3500). --define(wxAuiManagerEvent_GetPane, 3501). --define(wxAuiManagerEvent_SetButton, 3502). --define(wxAuiManagerEvent_GetButton, 3503). --define(wxAuiManagerEvent_SetDC, 3504). --define(wxAuiManagerEvent_GetDC, 3505). --define(wxAuiManagerEvent_Veto, 3506). --define(wxAuiManagerEvent_GetVeto, 3507). --define(wxAuiManagerEvent_SetCanVeto, 3508). --define(wxAuiManagerEvent_CanVeto, 3509). --define(wxLogNull_new, 3510). --define(wxLogNull_destroy, 3511). +-define(wxSystemOptions_GetOption, 3492). +-define(wxSystemOptions_GetOptionInt, 3493). +-define(wxSystemOptions_HasOption, 3494). +-define(wxSystemOptions_IsFalse, 3495). +-define(wxSystemOptions_SetOption_2_1, 3496). +-define(wxSystemOptions_SetOption_2_0, 3497). +-define(wxAuiNotebookEvent_SetSelection, 3498). +-define(wxAuiNotebookEvent_GetSelection, 3499). +-define(wxAuiNotebookEvent_SetOldSelection, 3500). +-define(wxAuiNotebookEvent_GetOldSelection, 3501). +-define(wxAuiNotebookEvent_SetDragSource, 3502). +-define(wxAuiNotebookEvent_GetDragSource, 3503). +-define(wxAuiManagerEvent_SetManager, 3504). +-define(wxAuiManagerEvent_GetManager, 3505). +-define(wxAuiManagerEvent_SetPane, 3506). +-define(wxAuiManagerEvent_GetPane, 3507). +-define(wxAuiManagerEvent_SetButton, 3508). +-define(wxAuiManagerEvent_GetButton, 3509). +-define(wxAuiManagerEvent_SetDC, 3510). +-define(wxAuiManagerEvent_GetDC, 3511). +-define(wxAuiManagerEvent_Veto, 3512). +-define(wxAuiManagerEvent_GetVeto, 3513). +-define(wxAuiManagerEvent_SetCanVeto, 3514). +-define(wxAuiManagerEvent_CanVeto, 3515). +-define(wxLogNull_new, 3516). +-define(wxLogNull_destroy, 3517). diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl index 0d8dd4852e..8f364049b4 100644 --- a/lib/wx/test/wx_event_SUITE.erl +++ b/lib/wx/test/wx_event_SUITE.erl @@ -47,7 +47,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [connect, disconnect, connect_msg_20, connect_cb_20, - mouse_on_grid, spin_event, connect_in_callback]. + mouse_on_grid, spin_event, connect_in_callback, recursive]. groups() -> []. @@ -331,3 +331,35 @@ connect_in_callback(Config) -> wx_test_lib:flush(), wx_test_lib:wx_destroy(Frame, Config). + +%% Test that event callback which triggers another callback works +%% i.e. the callback invoker in driver will recurse +recursive(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +recursive(Config) -> + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, "Connect in callback"), + Panel = wxPanel:new(Frame, []), + Sz = wxBoxSizer:new(?wxVERTICAL), + ListBox = wxListBox:new(Panel, ?wxID_ANY, [{choices, ["foo", "bar", "baz"]}]), + wxSizer:add(Sz, ListBox, [{proportion, 1},{flag, ?wxEXPAND}]), + wxWindow:setSizer(Panel, Sz), + wxListBox:connect(ListBox, command_listbox_selected, + [{callback, + fun(#wx{event=#wxCommand{commandInt=Id}}, _) -> + io:format("Selected ~p~n",[Id]) + end}]), + wxListBox:setSelection(ListBox, 0), + wxListBox:connect(ListBox, size, + [{callback, + fun(#wx{event=#wxSize{}}, _) -> + io:format("Size init ~n",[]), + case wxListBox:getCount(ListBox) > 0 of + true -> wxListBox:delete(ListBox, 0); + false -> ok + end, + io:format("Size done ~n",[]) + end}]), + wxFrame:show(Frame), + wx_test_lib:flush(), + + wx_test_lib:wx_destroy(Frame, Config). diff --git a/lib/xmerl/doc/examples/test_html.erl b/lib/xmerl/doc/examples/test_html.erl index 3ca15f30f8..3ca15f30f8 100755..100644 --- a/lib/xmerl/doc/examples/test_html.erl +++ b/lib/xmerl/doc/examples/test_html.erl diff --git a/lib/xmerl/doc/examples/xml/test.xml b/lib/xmerl/doc/examples/xml/test.xml index e803a83560..e803a83560 100755..100644 --- a/lib/xmerl/doc/examples/xml/test.xml +++ b/lib/xmerl/doc/examples/xml/test.xml diff --git a/lib/xmerl/doc/examples/xml/test2.xml b/lib/xmerl/doc/examples/xml/test2.xml index 0cb11194fc..0cb11194fc 100755..100644 --- a/lib/xmerl/doc/examples/xml/test2.xml +++ b/lib/xmerl/doc/examples/xml/test2.xml diff --git a/lib/xmerl/doc/examples/xml/test3.xml b/lib/xmerl/doc/examples/xml/test3.xml index dbdc1e62c2..dbdc1e62c2 100755..100644 --- a/lib/xmerl/doc/examples/xml/test3.xml +++ b/lib/xmerl/doc/examples/xml/test3.xml diff --git a/lib/xmerl/doc/examples/xml/test4.xml b/lib/xmerl/doc/examples/xml/test4.xml index e9d85b8d8f..e9d85b8d8f 100755..100644 --- a/lib/xmerl/doc/examples/xml/test4.xml +++ b/lib/xmerl/doc/examples/xml/test4.xml diff --git a/lib/xmerl/doc/examples/xml/test5.xml b/lib/xmerl/doc/examples/xml/test5.xml index e9d85b8d8f..e9d85b8d8f 100755..100644 --- a/lib/xmerl/doc/examples/xml/test5.xml +++ b/lib/xmerl/doc/examples/xml/test5.xml diff --git a/lib/xmerl/doc/examples/xml/testdtd.dtd b/lib/xmerl/doc/examples/xml/testdtd.dtd index 2ce1c513a6..2ce1c513a6 100755..100644 --- a/lib/xmerl/doc/examples/xml/testdtd.dtd +++ b/lib/xmerl/doc/examples/xml/testdtd.dtd diff --git a/lib/xmerl/doc/examples/xml/xmerl.xml b/lib/xmerl/doc/examples/xml/xmerl.xml index f02282dbef..f02282dbef 100755..100644 --- a/lib/xmerl/doc/examples/xml/xmerl.xml +++ b/lib/xmerl/doc/examples/xml/xmerl.xml diff --git a/lib/xmerl/doc/src/make.dep b/lib/xmerl/doc/src/make.dep deleted file mode 100644 index 9c303fc41c..0000000000 --- a/lib/xmerl/doc/src/make.dep +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: book.tex part.tex ref_man.tex xmerl.tex xmerl_eventp.tex \ - xmerl_scan.tex xmerl_ug.tex xmerl_xpath.tex \ - xmerl_xs.tex xmerl_xsd.tex xmerl_sax_parser.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - -xmerl_ug.tex: motorcycles.txt motorcycles2html.erl motorcycles_dtd.txt \ - new_motorcycles.txt new_motorcycles2.txt - diff --git a/lib/xmerl/doc/src/part_notes.xml b/lib/xmerl/doc/src/part_notes.xml index 827ffd90e9..827ffd90e9 100755..100644 --- a/lib/xmerl/doc/src/part_notes.xml +++ b/lib/xmerl/doc/src/part_notes.xml diff --git a/lib/xmerl/include/xmerl.hrl b/lib/xmerl/include/xmerl.hrl index 7bb3f4de9b..3760a5cce0 100755..100644 --- a/lib/xmerl/include/xmerl.hrl +++ b/lib/xmerl/include/xmerl.hrl @@ -61,10 +61,11 @@ }). %% namespace node - i.e. a {Prefix, URI} pair -%% TODO: these are not currently used?? /RC -record(xmlNsNode,{ - prefix, - uri = [] + parents = [], % [{atom(),integer()}] + pos, % integer() + prefix, % string() + uri = [] % [] | atom() }). %% XML Element @@ -103,9 +104,10 @@ %% processing instruction -record(xmlPI,{ - name, % atom() - pos, % integer() - value % IOlist() + name, % atom() + parents = [], % [{atom(),integer()}] + pos, % integer() + value % IOlist() }). -record(xmlDocument,{ @@ -154,6 +156,9 @@ declarations = [], % [{Name, Attrs}] doctype_name, doctype_DTD = internal, % internal | DTDId + comments = true, + document = false, + default_attrs = false, rules, keep_rules = false, % delete (ets) tab if false namespace_conformant = false, % true | false diff --git a/lib/xmerl/include/xmerl_xlink.hrl b/lib/xmerl/include/xmerl_xlink.hrl index 375e244c23..375e244c23 100755..100644 --- a/lib/xmerl/include/xmerl_xlink.hrl +++ b/lib/xmerl/include/xmerl_xlink.hrl diff --git a/lib/xmerl/src/xmerl_lib.erl b/lib/xmerl/src/xmerl_lib.erl index 6402f1cbeb..aeb821f411 100644 --- a/lib/xmerl/src/xmerl_lib.erl +++ b/lib/xmerl/src/xmerl_lib.erl @@ -160,8 +160,9 @@ expand_element(E = #xmlText{}, Pos, Parents, Norm) -> E#xmlText{pos = Pos, parents = Parents, value = expand_text(E#xmlText.value, Norm)}; -expand_element(E = #xmlPI{}, Pos, _Parents, Norm) -> +expand_element(E = #xmlPI{}, Pos, Parents, Norm) -> E#xmlPI{pos = Pos, + parents = Parents, value = expand_text(E#xmlPI.value, Norm)}; expand_element(E = #xmlComment{}, Pos, Parents, Norm) -> E#xmlComment{pos = Pos, diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc index 3b9eaa309c..ec9178ea25 100644 --- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc @@ -944,14 +944,19 @@ parse_att_value(?STRING_REST("&", Rest), State, Stop, Acc) -> {unparsed, Name, _} -> ?fatal_error(State1, "Unparsed entity reference in attribute value: " ++ Name) end; -parse_att_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) -> +parse_att_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) -> {lists:reverse(Acc), Rest, State}; -parse_att_value(?STRING_UNBOUND_REST($<, _Rest), State, _Stop, _Acc) -> +parse_att_value(?STRING_UNBOUND_REST($<, _Rest), State, _Stop, _Acc) -> ?fatal_error(State, "< not allowed in attribute value"); -parse_att_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) -> - parse_att_value(Rest, State, Stop, [C|Acc]); -parse_att_value(Bytes, State, Stop, Acc) -> - unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_att_value/4], +parse_att_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) -> + if + ?is_char(C) -> + parse_att_value(Rest, State, Stop, [C|Acc]); + true -> + ?fatal_error(State, lists:flatten(io_lib:format("Bad character in attribute value: ~p", [C]))) + end; +parse_att_value(Bytes, State, Stop, Acc) -> + unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_att_value/4], undefined). @@ -1120,10 +1125,10 @@ parse_content(?STRING_UNBOUND_REST(C, Rest), State, Acc, _IgnorableWS) -> ?is_char(C) -> parse_content(Rest, State, [C|Acc], false); true -> - ?fatal_error(State, "Bad character in content: " ++ C) - end; -parse_content(Bytes, State, Acc, IgnorableWS) -> - unicode_incomplete_check([Bytes, State, Acc, IgnorableWS, fun parse_content/4], + ?fatal_error(State, lists:flatten(io_lib:format("Bad character in content: ~p", [C]))) + end; +parse_content(Bytes, State, Acc, IgnorableWS) -> + unicode_incomplete_check([Bytes, State, Acc, IgnorableWS, fun parse_content/4], undefined). @@ -2522,11 +2527,16 @@ parse_entity_value(?STRING_REST("%", Rest), #xmerl_sax_parser_state{file_type=Ty end end; -parse_entity_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) -> +parse_entity_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) -> {lists:reverse(Acc), Rest, State}; -parse_entity_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) -> - parse_entity_value(Rest, State, Stop, [C|Acc]); -parse_entity_value(Bytes, State, Stop, Acc) -> +parse_entity_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) -> + if + ?is_char(C) -> + parse_entity_value(Rest, State, Stop, [C|Acc]); + true -> + ?fatal_error(State, lists:flatten(io_lib:format("Bad character in entity value: ~p", [C]))) + end; +parse_entity_value(Bytes, State, Stop, Acc) -> unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_entity_value/4], undefined). diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index 25c6547497..ec7ea534d6 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -100,7 +100,21 @@ %% <dd>Set default character set used (default UTF-8). %% This character set is used only if not explicitly given by the XML %% declaration. </dd> +%% <dt><code>{document, Flag}</code></dt> +%% <dd>Set to 'true' if xmerl should return a complete XML document +%% as an xmlDocument record (default 'false').</dd> +%% <dt><code>{comments, Flag}</code></dt> +%% <dd>Set to 'false' if xmerl should skip comments otherwise they will +%% be returned as xmlComment records (default 'true').</dd> +%% <dt><code>{default_attrs, Flag}</code></dt> +%% <dd>Set to 'true' if xmerl should add to elements missing attributes +%% with a defined default value (default 'false').</dd> %% </dl> +%% @type document() = xmlElement() | xmlDocument(). <p> +%% The document returned by <tt>xmerl_scan:string/[1,2]</tt> and +%% <tt>xmerl_scan:file/[1,2]</tt>. The type of the returned record depends on +%% the value of the document option passed to the function. +%% </p> -module(xmerl_scan). @@ -224,7 +238,7 @@ cont_state(X, S=#xmerl_scanner{fun_states = FS}) -> file(F) -> file(F, []). -%% @spec file(Filename::string(), Options::option_list()) -> {xmlElement(),Rest} +%% @spec file(Filename::string(), Options::option_list()) -> {document(),Rest} %% Rest = list() %%% @doc Parse file containing an XML document file(F, Options) -> @@ -264,7 +278,7 @@ int_file_decl(F, Options,_ExtCharset) -> string(Str) -> string(Str, []). -%% @spec string(Text::list(),Options::option_list()) -> {xmlElement(),Rest} +%% @spec string(Text::list(),Options::option_list()) -> {document(),Rest} %% Rest = list() %%% @doc Parse string containing an XML document string(Str, Options) -> @@ -381,6 +395,12 @@ initial_state([{quiet, F}|T], S) when F==true; F==false -> initial_state(T, S#xmerl_scanner{quiet = F}); initial_state([{doctype_DTD,DTD}|T], S) -> initial_state(T,S#xmerl_scanner{doctype_DTD = DTD}); +initial_state([{document, F}|T], S) when is_boolean(F) -> + initial_state(T,S#xmerl_scanner{document = F}); +initial_state([{comments, F}|T], S) when is_boolean(F) -> + initial_state(T,S#xmerl_scanner{comments = F}); +initial_state([{default_attrs, F}|T], S) when is_boolean(F) -> + initial_state(T,S#xmerl_scanner{default_attrs = F}); initial_state([{text_decl,Bool}|T], S) -> initial_state(T,S#xmerl_scanner{text_decl=Bool}); initial_state([{environment,Env}|T], S) -> @@ -518,6 +538,7 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, line = L, col = C, environment=Env, encoding=Charset, + document=Document, validation=ValidateResult}) -> S1 = Event(#xmerl_event{event = started, line = L, @@ -530,8 +551,8 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, Str=if Charset == "utf-8" -> Str0; - Charset=/=undefined -> % Default character set is UTF-8 - xmerl_ucs:to_unicode(Str0,list_to_atom(Charset)); + Charset =/= undefined -> % Default character set is UTF-8 + xmerl_ucs:to_unicode(Str0, list_to_atom(Charset)); true -> %% Charset is undefined if no external input is %% given, and no auto detection of character %% encoding was made. @@ -539,17 +560,17 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, end, %% M1 = erlang:memory(), %% io:format("Memory status before prolog: ~p~n",[M1]), - {T1, S2} = scan_prolog(Str, S1, _StartPos = 1), + {Prolog, Pos, T1, S2} = scan_prolog(Str, S1, _StartPos = 1), %% M2 = erlang:memory(), %% io:format("Memory status after prolog: ~p~n",[M2]), %%io:format("scan_document 2, prolog parsed~n",[]), - T2 = scan_mandatory("<",T1,1,S2,expected_element_start_tag), + T2 = scan_mandatory("<", T1, 1, S2, expected_element_start_tag), %% M3 = erlang:memory(), %% io:format("Memory status before element: ~p~n",[M3]), - {Res, T3, S3} =scan_element(T2,S2,_StartPos = 1), + {Res, T3, S3} = scan_element(T2,S2,Pos), %% M4 = erlang:memory(), %% io:format("Memory status after element: ~p~n",[M4]), - {Tail, S4}=scan_misc(T3, S3, _StartPos = 1), + {Misc, _Pos1, Tail, S4}=scan_misc(T3, S3, Pos + 1), %% M5 = erlang:memory(), %% io:format("Memory status after misc: ~p~n",[M5]), @@ -558,44 +579,52 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, col = S4#xmerl_scanner.col, data = document}, S4), - {Res2,S6} = case validation_mode(ValidateResult) of + {Res2, S6} = case validation_mode(ValidateResult) of off -> - {Res,cleanup(S5)}; + {Res, cleanup(S5)}; dtd when Env == element; Env == prolog -> check_decl2(S5), - case xmerl_validate:validate(S5,Res) of - {'EXIT',{error,Reason}} -> - S5b=cleanup(S5), - ?fatal({failed_validation,Reason}, S5b); - {'EXIT',Reason} -> - S5b=cleanup(S5), - ?fatal({failed_validation,Reason}, S5b); - {error,Reason} -> - S5b=cleanup(S5), - ?fatal({failed_validation,Reason}, S5b); - {error,Reason,_Next} -> - S5b=cleanup(S5), - ?fatal({failed_validation,Reason}, S5b); + case xmerl_validate:validate(S5, Res) of + {'EXIT', {error, Reason}} -> + S5b = cleanup(S5), + ?fatal({failed_validation, Reason}, S5b); + {'EXIT', Reason} -> + S5b = cleanup(S5), + ?fatal({failed_validation, Reason}, S5b); + {error, Reason} -> + S5b = cleanup(S5), + ?fatal({failed_validation, Reason}, S5b); + {error, Reason, _Next} -> + S5b = cleanup(S5), + ?fatal({failed_validation, Reason}, S5b); _XML -> - {Res,cleanup(S5)} + {Res, cleanup(S5)} end; schema -> - case schemaLocations(Res,S5) of - {ok,Schemas} -> + case schemaLocations(Res, S5) of + {ok, Schemas} -> cleanup(S5), %%io:format("Schemas: ~p~nRes: ~p~ninhertih_options(S): ~p~n", %% [Schemas,Res,inherit_options(S5)]), - XSDRes = xmerl_xsd:process_validate(Schemas,Res, + XSDRes = xmerl_xsd:process_validate(Schemas, Res, inherit_options(S5)), - handle_schema_result(XSDRes,S5); + handle_schema_result(XSDRes, S5); _ -> - {Res,cleanup(S5)} + {Res, cleanup(S5)} end; _ -> - {Res,cleanup(S5)} + {Res, cleanup(S5)} end, - {Res2, Tail, S6}. + Res3 = + case Document of + true -> + Content = lists:reverse(Prolog, [Res2 | lists:reverse(Misc)]), + #xmlDocument{content = Content}; + false -> + Res2 + end, + {Res3, Tail, S6}. scan_decl(Str, S=#xmerl_scanner{event_fun = Event, @@ -609,11 +638,11 @@ scan_decl(Str, S=#xmerl_scanner{event_fun = Event, data = document}, S), case scan_prolog(Str, S1, _StartPos = 1) of - {T2="<"++_, S2} -> + {_,_,T2="<"++_, S2} -> {{S2#xmerl_scanner.user_state,T2},[],S2}; - {[], S2}-> + {_,_,[], S2}-> {[],[],S2}; - {T2, S2} -> + {_,_,T2, S2} -> {_,_,S3} = scan_content(T2,S2,[],_Attrs=[],S2#xmerl_scanner.space, _Lang=[],_Parents=[],#xmlNamespace{}), {T2,[],S3} @@ -624,14 +653,17 @@ scan_decl(Str, S=#xmerl_scanner{event_fun = Event, %%% prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? %%% %% empty text declarations are handled by the first function clause. -scan_prolog([], S=#xmerl_scanner{continuation_fun = F}, Pos) -> +scan_prolog(T, S, Pos) -> + scan_prolog(T, S, Pos, []). +scan_prolog([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_prolog(MoreBytes, S1, Pos) end, - fun(S1) -> {[], S1} end, + F(fun(MoreBytes, S1) -> scan_prolog(MoreBytes, S1, Pos, Acc) end, + fun(S1) -> {Acc, Pos, [], S1} end, S); -scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos) - when ?whitespace(hd(T)) -> - {Charset,T3, S3}= +scan_prolog("<?xml"++T, + S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L}, + Pos,Acc) when ?whitespace(hd(T)) -> + {Charset, T3, S3} = if Col==1,L==1,S0#xmerl_scanner.text_decl==true -> ?dbg("prolog(\"<?xml\")~n", []), @@ -639,13 +671,13 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos) {_,T1,S1} = mandatory_strip(T,S), {Decl,T2, S2}=scan_text_decl(T1,S1), Encoding=Decl#xmlDecl.encoding, - {Encoding,T2, S2#xmerl_scanner{encoding=Encoding}}; + {Encoding, T2, S2#xmerl_scanner{encoding=Encoding}}; Col==1,L==1 -> ?dbg("prolog(\"<?xml\")~n", []), ?bump_col(5), {Decl,T2, S2}=scan_xml_decl(T, S), Encoding=Decl#xmlDecl.encoding, - {Encoding,T2, S2#xmerl_scanner{encoding=Encoding}}; + {Encoding, T2, S2#xmerl_scanner{encoding=Encoding}}; true -> ?fatal({xml_declaration_must_be_first_in_doc,Col,L},S0) end, @@ -659,7 +691,7 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos) %% Now transform to declared character set. if Charset==Charset0 -> % Document already transformed to this charset! - scan_prolog(T3, S3, Pos); + scan_prolog(T3, S3, Pos, Acc); Charset0=/=undefined -> %% For example may an external entity %% have the BOM for utf-16 and the internal @@ -668,17 +700,18 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos) %% 'iso-10646-utf-1', and Charset will be 'utf-16', all %% legal. %% - scan_prolog(T3,S3#xmerl_scanner{encoding=Charset0},Pos); + scan_prolog(T3,S3#xmerl_scanner{encoding=Charset0},Pos,Acc); Charset == "utf-8" -> - scan_prolog(T3, S3, Pos); + scan_prolog(T3, S3, Pos, Acc); Charset=/=undefined -> % Document not previously transformed T4=xmerl_ucs:to_unicode(T3,list_to_atom(Charset)), - scan_prolog(T4, S3, Pos); + scan_prolog(T4, S3, Pos, Acc); true -> % No encoding info given - scan_prolog(T3, S3, Pos) + scan_prolog(T3, S3, Pos, Acc) end; -scan_prolog("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog, - encoding=_Charset}, Pos) -> +scan_prolog("<!DOCTYPE" ++ T, + S0=#xmerl_scanner{environment=prolog,encoding=_Charset}, + Pos, Acc) -> ?dbg("prolog(\"<!DOCTYPE\")~n", []), ?bump_col(9), %% If no known character set assume it is UTF-8 @@ -687,10 +720,13 @@ scan_prolog("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog, true -> T end, {T2, S1} = scan_doctype(T1, S), - scan_misc(T2, S1, Pos); -scan_prolog(Str="%"++_T,S=#xmerl_scanner{environment={external,_}},_Pos) -> - scan_ext_subset(Str,S); -scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset},Pos) -> + scan_misc(T2, S1, Pos, Acc); +scan_prolog(Str="%"++_T,S=#xmerl_scanner{environment={external,_}}, + Pos,Acc) -> + {T, S1} = scan_ext_subset(Str,S), + {Acc, Pos, T, S1}; +scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset}, + Pos,Acc) -> ?dbg("prolog(\"<\")~n", []), %% Check for Comments, PI before possible DOCTYPE declaration @@ -700,26 +736,28 @@ scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset},Pos) -> %% Charset==undefined -> xmerl_ucs:to_unicode(Str,'utf-8'); true -> Str end, - {T1, S1}=scan_misc(T, S, Pos), - scan_prolog2(T1,S1,Pos). + {Acc1, Pos1, T1, S1}=scan_misc(T, S, Pos, Acc), + scan_prolog2(T1,S1,Pos1,Acc1). -scan_prolog2([], S=#xmerl_scanner{continuation_fun = F}, Pos) -> +scan_prolog2([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_prolog2(MoreBytes, S1, Pos) end, - fun(S1) -> {[], S1} end, + F(fun(MoreBytes, S1) -> scan_prolog2(MoreBytes, S1, Pos, Acc) end, + fun(S1) -> {Acc, Pos, [], S1} end, S); -scan_prolog2("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog}, Pos) -> +scan_prolog2("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog}, + Pos, Acc) -> ?dbg("prolog(\"<!DOCTYPE\")~n", []), ?bump_col(9), {T1, S1} = scan_doctype(T, S), - scan_misc(T1, S1, Pos); -scan_prolog2(Str = "<!" ++ _, S, _Pos) -> + scan_misc(T1, S1, Pos, Acc); +scan_prolog2(Str = "<!" ++ _, S, Pos, Acc) -> ?dbg("prolog(\"<!\")~n", []), %% In e.g. a DTD, we jump directly to markup declarations - scan_ext_subset(Str, S); -scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) -> + {T, S1} = scan_ext_subset(Str, S), + {Acc, Pos, T, S1}; +scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos,Acc) -> ?dbg("prolog(\"<\")~n", []), %% Here we consider the DTD provided by doctype_DTD option, @@ -733,7 +771,7 @@ scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) -> end, %% Check for more Comments and PI after DOCTYPE declaration % ?bump_col(1), - scan_misc(Str, S1, Pos). + scan_misc(Str, S1, Pos, Acc). @@ -743,26 +781,46 @@ scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) -> %% - Neither of Comment and PI are returned in the resulting parsed %% structure. %% - scan_misc/3 implements Misc* as that is how the rule is always used -scan_misc([], S=#xmerl_scanner{continuation_fun = F}, Pos) -> +scan_misc(T, S, Pos) -> + scan_misc(T, S, Pos, []). +scan_misc([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_misc(MoreBytes, S1, Pos) end, - fun(S1) -> {[], S1} end, + F(fun(MoreBytes, S1) -> scan_misc(MoreBytes, S1, Pos, Acc) end, + fun(S1) -> {Acc, Pos, [], S1} end, S); -scan_misc("<!--" ++ T, S0, Pos) -> % Comment +scan_misc("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Acc) -> % Comment ?bump_col(4), - {_, T1, S1} = scan_comment(T, S, Pos, _Parents = [], _Lang = []), - scan_misc(T1,S1,Pos); -scan_misc("<?" ++ T, S0, Pos) -> % PI + {C, T1, S1} = scan_comment(T, S, Pos, _Parents = [], _Lang = []), + case CF of + true -> + {Acc2, Pos2, S3} = + case F(C, Acc, S1) of + {Acc1, S2} -> + {Acc1, Pos + 1, S2}; + {Acc1, Pos1, S2} -> + {Acc1, Pos1, S2} + end, + scan_misc(T1, S3, Pos2, Acc2); + false -> + scan_misc(T1, S1, Pos, Acc) + end; +scan_misc("<?" ++ T, S0=#xmerl_scanner{acc_fun = F}, Pos, Acc) -> % PI ?dbg("prolog(\"<?\")~n", []), ?bump_col(2), - {_PI, T1, S1} = scan_pi(T, S, Pos), - scan_misc(T1,S1,Pos); -scan_misc(T=[H|_T], S, Pos) when ?whitespace(H) -> + {PI, T1, S1} = scan_pi(T, S, Pos, []), + {Acc2, Pos2, S3} = case F(PI, Acc, S1) of + {Acc1, S2} -> + {Acc1, Pos + 1, S2}; + {Acc1, Pos1, S2} -> + {Acc1, Pos1, S2} + end, + scan_misc(T1,S3,Pos2,Acc2); +scan_misc(T=[H|_T], S, Pos, Acc) when ?whitespace(H) -> ?dbg("prolog(whitespace)~n", []), {_,T1,S1}=strip(T,S), - scan_misc(T1,S1,Pos); -scan_misc(T,S,_Pos) -> - {T,S}. + scan_misc(T1,S1,Pos,Acc); +scan_misc(T,S,Pos,Acc) -> + {Acc,Pos,T,S}. cleanup(S=#xmerl_scanner{keep_rules = false, @@ -789,7 +847,8 @@ scan_xml_decl(T, S) -> Attr = #xmlAttribute{name = version, parents = [{xml, _XMLPos = 1}], value = Vsn}, - scan_xml_decl(T4, S4, #xmlDecl{attributes = [Attr]}). + scan_xml_decl(T4, S4, #xmlDecl{vsn = Vsn, + attributes = [Attr]}). scan_xml_decl([], S=#xmerl_scanner{continuation_fun = F}, Decl) -> ?dbg("cont()...~n", []), @@ -1025,50 +1084,53 @@ xml_vsn([H|T], S=#xmerl_scanner{col = C}, Delim, Acc) -> %%%%%%% [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' -scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Pos) -> +scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Pos, Ps) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Pos) end, + F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Pos, Ps) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); -scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos) +scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos, Ps) when H1==$x;H1==$X -> %% names beginning with [xX][mM][lL] are reserved for future use. ?bump_col(3), if ((H2==$m) or (H2==$M)) and ((H3==$l) or (H3==$L)) -> - scan_wellknown_pi(T,S,Pos); + scan_wellknown_pi(T,S,Pos,Ps); true -> {Target, _NamespaceInfo, T1, S1} = scan_name(Str, S), - scan_pi(T1, S1, Target, L, C, Pos, []) + scan_pi(T1, S1, Target, L, C, Pos, Ps, []) end; -scan_pi(Str, S=#xmerl_scanner{line = L, col = C}, Pos) -> +scan_pi(Str, S=#xmerl_scanner{line = L, col = C}, Pos, Ps) -> {Target, _NamespaceInfo, T1, S1} = scan_name(Str, S), - scan_pi(T1, S1, Target, L, C, Pos,[]). + scan_pi(T1, S1, Target, L, C, Pos, Ps, []). %%% More info on xml-stylesheet can be found at: %%% "Associating Style Sheets with XML documents", Version 1.0, %%% W3C Recommendation 29 June 1999 (http://www.w3.org/TR/xml-stylesheet/) -scan_wellknown_pi("-stylesheet"++T, S0=#xmerl_scanner{line=L,col=C},Pos) -> +scan_wellknown_pi("-stylesheet"++T, S0=#xmerl_scanner{line=L,col=C},Pos,Ps) -> ?dbg("prolog(\"<?xml-stylesheet\")~n", []), ?bump_col(16), - scan_pi(T, S, "xml-stylesheet",L,C,Pos,[]); -scan_wellknown_pi(Str,S,_Pos) -> + scan_pi(T, S, "xml-stylesheet",L,C,Pos,Ps,[]); +scan_wellknown_pi(Str,S,_Pos,_Ps) -> ?fatal({invalid_target_name, lists:sublist(Str, 1, 10)}, S). -scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target,L, C, Pos, Acc) -> +scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target, + L, C, Pos, Ps, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Target, L, C, Pos, Acc) end, + F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Target, + L, C, Pos, Ps, Acc) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event}, - Target, L, C, Pos, Acc) -> + Target, L, C, Pos, Ps, Acc) -> ?bump_col(2), PI = #xmlPI{name = Target, + parents = Ps, pos = Pos, value = lists:reverse(Acc)}, S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, @@ -1077,22 +1139,25 @@ scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, data = PI}, S), {Ret, S2} = Hook(PI, S1), {Ret, T, S2}; -scan_pi([H|T], S, Target, L, C, Pos, Acc) when ?whitespace(H) -> +scan_pi([H|T], S, Target, L, C, Pos, Ps, Acc) when ?whitespace(H) -> ?strip1, - scan_pi2(T1, S1, Target, L, C, Pos, Acc); -scan_pi([H|_T],S,_Target, _L, _C, _Pos, _Acc) -> + scan_pi2(T1, S1, Target, L, C, Pos, Ps, Acc); +scan_pi([H|_T],S,_Target, _L, _C, _Pos, _Ps, _Acc) -> ?fatal({expected_whitespace_OR_end_of_PI,{char,H}}, S). -scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target,L, C, Pos, Acc) -> +scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target, + L, C, Pos, Ps, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_pi2(MoreBytes, S1, Target, L, C, Pos, Acc) end, + F(fun(MoreBytes, S1) -> scan_pi2(MoreBytes, S1, Target, + L, C, Pos, Ps, Acc) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event}, - Target, L, C, Pos, Acc) -> + Target, L, C, Pos, Ps, Acc) -> ?bump_col(2), PI = #xmlPI{name = Target, + parents = Ps, pos = Pos, value = lists:reverse(Acc)}, S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, @@ -1101,10 +1166,10 @@ scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, data = PI}, S), {Ret, S2} = Hook(PI, S1), {Ret, T, S2}; -scan_pi2(Str, S0, Target, L, C, Pos, Acc) -> +scan_pi2(Str, S0, Target, L, C, Pos, Ps, Acc) -> ?bump_col(1), {Ch,T} = wfc_legal_char(Str,S), - scan_pi2(T, S, Target, L, C, Pos, [Ch|Acc]). + scan_pi2(T, S, Target, L, C, Pos, Ps, [Ch|Acc]). @@ -1575,7 +1640,7 @@ scan_markup_decl("<!--" ++ T, S0) -> scan_comment(T, S); scan_markup_decl("<?" ++ T, S0) -> ?bump_col(2), - {_PI, T1, S1} = scan_pi(T, S,_Pos=markup), + {_PI, T1, S1} = scan_pi(T, S,_Pos=markup,[]), strip(T1, S1); scan_markup_decl("<!ELEMENT" ++ T, #xmerl_scanner{rules_read_fun = Read, @@ -1981,7 +2046,7 @@ scan_element(T, S, Pos) -> scan_element(T, S=#xmerl_scanner{line=L,col=C}, Pos, SpaceDefault,Lang, Parents, NS) -> {Name, NamespaceInfo, T1, S1} = scan_name(T, S), - vc_Element_valid(Name,S), + vc_Element_valid(Name,NamespaceInfo,S), ?strip2, scan_element(T2, S2, Pos, Name, L, C, _Attrs = [], Lang, Parents, NamespaceInfo, NS, @@ -2016,7 +2081,8 @@ scan_element("/>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, Attrs = lists:reverse(Attrs0), E=processed_whole_element(S, Pos, Name, Attrs, Lang, Parents,NSI,Namespace), - wfc_unique_att_spec(Attrs,S), + #xmlElement{attributes = Attrs1} = E, + wfc_unique_att_spec(Attrs1,S), S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, line = L, col = C, @@ -2086,9 +2152,10 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, P+1 end, Attr = #xmlAttribute{name = AttName, + parents = [{Name, Pos}|Parents], pos = AttrPos, language = Lang, - namespace = NamespaceInfo, + nsinfo = NamespaceInfo, value = AttValue, normalized = IsNorm}, XMLBase=if @@ -2110,6 +2177,14 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, scan_element(T4, S5, Pos, Name, StartL, StartC, [Attr|Attrs], Lang, Parents, NSI, NewNS, SpaceDefault). +get_default_attrs(S = #xmerl_scanner{rules_read_fun = Read}, ElemName) -> + case Read(elem_def, ElemName, S) of + #xmlElement{attributes = Attrs} -> + [ {AttName, AttValue} || + {AttName, _, AttValue, _, _} <- Attrs, AttValue =/= no_value ]; + _ -> [] + end. + get_att_type(S=#xmerl_scanner{rules_read_fun=Read},AttName,ElemName) -> case Read(elem_def,ElemName,S) of #xmlElement{attributes = Attrs} -> @@ -2139,6 +2214,23 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook, Pos, Name, Attrs, Lang, Parents, NSI, Namespace) -> Language = check_language(Attrs, Lang), + AllAttrs = + case S#xmerl_scanner.default_attrs of + true -> + [ #xmlAttribute{name = AttName, + parents = [{Name, Pos} | Parents], + language = Lang, + nsinfo = NSI, + namespace = Namespace, + value = AttValue, + normalized = true} || + {AttName, AttValue} <- get_default_attrs(S, Name), + AttValue =/= no_value, + not lists:keymember(AttName, #xmlAttribute.name, Attrs) ]; + false -> + Attrs + end, + {ExpName, ExpAttrs} = case S#xmerl_scanner.namespace_conformant of true -> @@ -2153,14 +2245,15 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook, TempNamespace = Namespace#xmlNamespace{default = []}, ExpAttrsX = [A#xmlAttribute{ + namespace=Namespace, expanded_name=expanded_name( A#xmlAttribute.name, - A#xmlAttribute.namespace, + A#xmlAttribute.nsinfo, % NSI, - TempNamespace, S)} || A <- Attrs], + TempNamespace, S)} || A <- AllAttrs], {expanded_name(Name, NSI, Namespace, S), ExpAttrsX}; false -> - {Name, Attrs} + {Name, AllAttrs} end, #xmlElement{name = Name, @@ -2194,10 +2287,32 @@ check_namespace(_, _, _, NS) -> expanded_name(Name, [], #xmlNamespace{default = []}, _S) -> Name; -expanded_name(Name, [], #xmlNamespace{default = URI}, _S) -> - {URI, Name}; -expanded_name(_Name, {"xmlns", Local}, _NS, _S) -> % CHECK THIS /JB - {"xmlns",Local}; +expanded_name(Name, [], #xmlNamespace{default = URI}, S) -> + case URI of + 'http://www.w3.org/XML/1998/namespace' -> + ?fatal(cannot_bind_default_namespace_to_xml_namespace_name, S); + 'http://www.w3.org/2000/xmlns/' -> + ?fatal(cannot_bind_default_namespace_to_xmlns_namespace_name, S); + _ -> + {URI, Name} + end; +expanded_name(Name, N = {"xmlns", Local}, #xmlNamespace{nodes = Ns}, S) -> + {_, Value} = lists:keyfind(Local, 1, Ns), + case Name of + 'xmlns:xml' when Value =/= 'http://www.w3.org/XML/1998/namespace' -> + ?fatal({xml_prefix_cannot_be_redeclared, Value}, S); + 'xmlns:xmlns' -> + ?fatal({xmlns_prefix_cannot_be_declared, Value}, S); + _ -> + case Value of + 'http://www.w3.org/XML/1998/namespace' -> + ?fatal({cannot_bind_prefix_to_xml_namespace, Local}, S); + 'http://www.w3.org/2000/xmlns/' -> + ?fatal({cannot_bind_prefix_to_xmlns_namespace, Local}, S); + _ -> + N + end + end; expanded_name(_Name, {Prefix, Local}, #xmlNamespace{nodes = Ns}, S) -> case lists:keysearch(Prefix, 1, Ns) of {value, {_, URI}} -> @@ -2449,9 +2564,23 @@ scan_content("&" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) - _ -> scan_content(string_to_char_set(S1#xmerl_scanner.encoding,ExpRef)++T1,S1,Pos,Name,Attrs,Space,Lang,Parents,NS,Acc,[]) end; -scan_content("<!--" ++ T, S, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) -> - {_, T1, S1} = scan_comment(T, S, Pos, Parents, Lang), - scan_content(T1, S1, Pos+1, Name, Attrs, Space, Lang, Parents, NS, Acc,[]); +scan_content("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Name, Attrs, Space, + Lang, Parents, NS, Acc,[]) -> + ?bump_col(4), + {C, T1, S1} = scan_comment(T, S, Pos, Parents, Lang), + case CF of + true -> + {Acc2, Pos2, S3} = + case F(C, Acc, S1) of + {Acc1, S2} -> + {Acc1, Pos + 1, S2}; + {Acc1, Pos1, S2} -> + {Acc1, Pos1, S2} + end, + scan_content(T1, S3, Pos2, Name, Attrs, Space, Lang, Parents, NS, Acc2,[]); + false -> + scan_content(T1, S1, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) + end; scan_content("<" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) -> ?bump_col(1), {Markup, T1, S1} = @@ -2508,9 +2637,9 @@ scan_content_markup("![CDATA[" ++ T, S0, Pos, _Name, _Attrs, _Space, _Lang, Parents, _NS) -> ?bump_col(8), scan_cdata(T, S, Pos, Parents); -scan_content_markup("?"++T,S0,Pos,_Name,_Attrs,_Space,_Lang,_Parents,_NS) -> +scan_content_markup("?"++T,S0,Pos,_Name,_Attrs,_Space,_Lang,Parents,_NS) -> ?bump_col(1), - scan_pi(T, S, Pos); + scan_pi(T, S, Pos, Parents); scan_content_markup(T, S, Pos, _Name, _Attrs, Space, Lang, Parents, NS) -> scan_element(T, S, Pos, Space, Lang, Parents, NS). @@ -3259,12 +3388,18 @@ mandatory_delimeter_wfc(T,S) -> wfc_unique_att_spec([],_S) -> ok; -wfc_unique_att_spec([#xmlAttribute{name=N}|Atts],S) -> +wfc_unique_att_spec([#xmlAttribute{name=N,expanded_name=EN}|Atts],S) -> case lists:keymember(N,#xmlAttribute.name,Atts) of true -> ?fatal({error,{unique_att_spec_required,N}},S); _ -> - wfc_unique_att_spec(Atts,S) + case S#xmerl_scanner.namespace_conformant andalso + lists:keymember(EN, #xmlAttribute.expanded_name, Atts) of + true -> + ?fatal({error,{unique_att_spec_required,EN}},S); + _ -> + wfc_unique_att_spec(Atts,S) + end end. wfc_legal_char(Chars,S) when is_list(Chars)-> @@ -3313,6 +3448,11 @@ wfc_Internal_parsed_entity(internal,Value,S) -> wfc_Internal_parsed_entity(_,_,_) -> ok. +vc_Element_valid(_Name, {"xmlns", _}, + S = #xmerl_scanner{namespace_conformant = true}) -> + ?fatal({error,{illegal_element_prefix,xmlns}},S); +vc_Element_valid(Name, _, S) -> + vc_Element_valid(Name, S). vc_Element_valid(_Name,#xmerl_scanner{environment=internal_parsed_entity}) -> ok; @@ -3917,7 +4057,7 @@ schemaLocations(El,#xmerl_scanner{schemaLocation=SL}) -> schemaLocations(#xmlElement{attributes=Atts,xmlbase=_Base}) -> Pred = fun(#xmlAttribute{name=schemaLocation}) -> false; - (#xmlAttribute{namespace={_,"schemaLocation"}}) -> false; + (#xmlAttribute{nsinfo={_,"schemaLocation"}}) -> false; (_) -> true end, case lists:dropwhile(Pred,Atts) of diff --git a/lib/xmerl/src/xmerl_validate.erl b/lib/xmerl/src/xmerl_validate.erl index 893e23ca34..4028fef2b9 100644 --- a/lib/xmerl/src/xmerl_validate.erl +++ b/lib/xmerl/src/xmerl_validate.erl @@ -399,25 +399,28 @@ test_attribute_value(_Rule,Attr,_,_) -> %% +type valid_contents([rule()],[xmlElement()])-> %% [xmlElement() | {error,???}. -valid_contents(Rule,XMLS,Rules,S,WSActionMode)-> - case parse(Rule,XMLS,Rules,WSActionMode,S) of - {XML_N,[]}-> - lists:flatten(XML_N); - {_,[#xmlElement{name=Name}|_T]} -> - exit({error,{element,Name,isnt_comprise_in_the_rule,Rule}}); - {_,[#xmlText{}=Txt|_T]} -> - exit({error,{element,text,Txt,isnt_comprise_in_the_rule,Rule}}); - {error,Reason} -> - {error,Reason}; - {error,Reason,N} -> - {error,Reason,N} +valid_contents(Rule, XMLS, Rules, S, WSActionMode)-> + case parse(Rule, XMLS, Rules, WSActionMode, S) of + {error, Reason} -> + {error, Reason}; + {error, Reason, N} -> + {error, Reason, N}; + {XML_N, Rest} -> %The list may consist of xmlComment{} records + case lists:dropwhile(fun(X) when is_record(X, xmlComment) -> true; (_) -> false end, Rest) of + [] -> + lists:flatten(XML_N); + [#xmlElement{name=Name} |_T] -> + exit({error, {element, Name, isnt_comprise_in_the_rule, Rule}}); + [#xmlText{} = Txt |_T] -> + exit({error, {element, text, Txt, isnt_comprise_in_the_rule, Rule}}) + end end. -parse({'*',SubRule},XMLS,Rules,WSaction,S)-> - star(SubRule,XMLS,Rules,WSaction,[],S); -parse({'+',SubRule},XMLS,Rules,WSaction,S) -> - plus(SubRule,XMLS,Rules,WSaction,S); -parse({choice,CHOICE},XMLS,Rules,WSaction,S)-> +parse({'*', SubRule}, XMLS, Rules, WSaction, S)-> + star(SubRule, XMLS, Rules, WSaction, [], S); +parse({'+',SubRule}, XMLS, Rules, WSaction, S) -> + plus(SubRule, XMLS, Rules, WSaction, S); +parse({choice,CHOICE}, XMLS, Rules, WSaction, S)-> % case XMLS of % [] -> % io:format("~p~n",[{choice,CHOICE,[]}]); @@ -426,47 +429,49 @@ parse({choice,CHOICE},XMLS,Rules,WSaction,S)-> % [#xmlText{value=V}|_] -> % io:format("~p~n",[{choice,CHOICE,{text,V}}]) % end, - choice(CHOICE,XMLS,Rules,WSaction,S); -parse(empty,[],_Rules,_WSaction,_S) -> - {[],[]}; -parse({'?',SubRule},XMLS,Rules,_WSaction,S)-> - question(SubRule,XMLS,Rules,S); -parse({seq,List},XMLS,Rules,WSaction,S) -> - seq(List,XMLS,Rules,WSaction,S); -parse(El_Name,[#xmlElement{name=El_Name}=XML|T],Rules,_WSaction,S) + choice(CHOICE, XMLS, Rules, WSaction, S); +parse(empty, [], _Rules, _WSaction, _S) -> + {[], []}; +parse({'?', SubRule}, XMLS, Rules, _WSaction, S)-> + question(SubRule, XMLS, Rules, S); +parse({seq,List}, XMLS, Rules, WSaction, S) -> + seq(List, XMLS, Rules, WSaction, S); +parse(El_Name, [#xmlElement{name=El_Name} = XML |T], Rules, _WSaction, S) when is_atom(El_Name)-> - case do_validation(read_rules(Rules,El_Name),XML,Rules,S) of - {error,R} -> + case do_validation(read_rules(Rules, El_Name), XML, Rules, S) of + {error, R} -> % {error,R}; exit(R); - {error,R,_N}-> + {error, R, _N}-> % {error,R,N}; exit(R); XML_-> - {[XML_],T} + {[XML_], T} end; -parse(any,Cont,Rules,_WSaction,S) -> - case catch parse_any(Cont,Rules,S) of - Err = {error,_} -> Err; - ValidContents -> {ValidContents,[]} +parse(any, Cont, Rules, _WSaction, S) -> + case catch parse_any(Cont, Rules, S) of + Err = {error, _} -> Err; + ValidContents -> {ValidContents, []} end; -parse(El_Name,[#xmlElement{name=Name}|_T]=S,_Rules,_WSa,_S) when is_atom(El_Name)-> +parse(El_Name, [#xmlElement{name=Name} |_T] = XMLS, _Rules, _WSa, _S) when is_atom(El_Name) -> {error, - {element_seq_not_conform,{wait,El_Name},{is,Name}}, - {{next,S},{act,[]}} }; -parse(_El_Name,[#xmlPI{}=H|T],_Rules,_WSa,_S) -> - {[H],T}; -parse('#PCDATA',XML,_Rules,_WSa,_S)-> + {element_seq_not_conform,{wait, El_Name}, {is, Name}}, + {{next, XMLS}, {act, []}}}; +parse(El_Name, [#xmlComment{} |T], Rules, WSa, S) -> + parse(El_Name, T, Rules, WSa, S); +parse(_El_Name, [#xmlPI{} = H |T], _Rules, _WSa, _S) -> + {[H], T}; +parse('#PCDATA', XMLS, _Rules, _WSa, _S)-> %%% PCDATA it is 0 , 1 or more #xmlText{}. - parse_pcdata(XML); -parse(El_Name,[#xmlText{}|_T]=S,_Rules,_WSa,_S)-> + parse_pcdata(XMLS); +parse(El_Name, [#xmlText{}|_T] = XMLS, _Rules, _WSa, _S)-> {error, - {text_in_place_of,El_Name}, - {{next,S},{act,[]}}}; -parse([],_,_,_,_) -> - {error,no_rule}; -parse(Rule,[],_,_,_) -> - {error,{no_xml_element,Rule}}. + {text_in_place_of, El_Name}, + {{next, XMLS}, {act, []}}}; +parse([], _, _, _, _) -> + {error, no_rule}; +parse(Rule, [], _, _, _) -> + {error, {no_xml_element, Rule}}. parse_any([],_Rules,_S) -> []; @@ -618,11 +623,15 @@ el_name(#xmlElement{name=Name})-> parse_pcdata([#xmlText{}=H|T])-> parse_pcdata(T,[H]); +parse_pcdata([#xmlComment{}|T])-> + parse_pcdata(T,[]); parse_pcdata(H) -> {[],H}. parse_pcdata([#xmlText{}=H|T],Acc)-> parse_pcdata(T,Acc++[H]); +parse_pcdata([#xmlComment{}|T],Acc)-> + parse_pcdata(T,Acc); parse_pcdata(H,Acc) -> {Acc,H}. diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl index db3d3ac2d6..b3301f2faf 100644 --- a/lib/xmerl/src/xmerl_xpath.erl +++ b/lib/xmerl/src/xmerl_xpath.erl @@ -41,18 +41,13 @@ % xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("parent::processing-instruction('foo')")). %% </pre> %% -%% @type docEntity() = +%% @type nodeEntity() = %% xmlElement() %% | xmlAttribute() %% | xmlText() %% | xmlPI() %% | xmlComment() -%% @type nodeEntity() = -%% xmlElement() -%% | xmlAttribute() -%% | xmlText() -%% | xmlPI() -%% | xmlNamespace() +%% | xmlNsNode() %% | xmlDocument() %% @type option_list(). <p>Options allows to customize the behaviour of the %% XPath scanner. @@ -303,6 +298,17 @@ write_node(#xmlNode{pos = Pos, node = #xmlText{value = Txt, parents = Ps}}) -> {text, Pos, Txt, Ps}; +write_node(#xmlNode{pos = Pos, + node = #xmlComment{parents = Ps}}) -> + {comment, Pos, '', Ps}; +write_node(#xmlNode{pos = Pos, + node = #xmlPI{name = Name, + parents = Ps}}) -> + {processing_instruction, Pos, Name, Ps}; +write_node(#xmlNode{pos = Pos, + node = #xmlNsNode{parents = Ps, + prefix = Prefix}}) -> + {namespace, Pos, Prefix, Ps}; write_node(_) -> other. @@ -330,18 +336,16 @@ eval_path(rel, PathExpr, C = #xmlContext{}) -> Context = C#xmlContext{nodeset = NodeSet}, S = #state{context = Context}, path_expr(PathExpr, S); -eval_path(filter, {PathExpr, PredExpr}, C = #xmlContext{}) -> +eval_path(filter, {PathExpr, {pred, Pred}}, C = #xmlContext{}) -> S = #state{context = C}, - S1 = path_expr(PathExpr, S), - pred_expr(PredExpr, S1). + S1 = match_expr(PathExpr, S), + eval_pred(Pred, S1). -eval_primary_expr(FC = {function_call,_,_},S = #state{context = Context}) -> +eval_primary_expr(PrimExpr, S = #state{context = Context}) -> %% NewNodeSet = xmerl_xpath_pred:eval(FC, Context), - NewNodeSet = xmerl_xpath_lib:eval(primary_expr, FC, Context), + NewNodeSet = xmerl_xpath_lib:eval(primary_expr, PrimExpr, Context), NewContext = Context#xmlContext{nodeset = NewNodeSet}, - S#state{context = NewContext}; -eval_primary_expr(PrimExpr,_S) -> - exit({primary_expression,{not_implemented, PrimExpr}}). + S#state{context = NewContext}. %% axis(Axis,NodeTest,Context::xmlContext()) -> xmlContext() @@ -384,8 +388,8 @@ axis1(preceding, Tok, N, Acc, Context) -> match_preceding(Tok, N, Acc, Context); axis1(attribute, Tok, N, Acc, Context) -> match_attribute(Tok, N, Acc, Context); -%axis1(namespace, Tok, N, Acc, Context) -> -% match_namespace(Tok, N, Acc, Context); +axis1(namespace, Tok, N, Acc, Context) -> + match_namespace(Tok, N, Acc, Context); axis1(ancestor_or_self, Tok, N, Acc, Context) -> match_ancestor_or_self(Tok, N, Acc, Context); axis1(descendant_or_self, Tok, N, Acc, Context) -> @@ -627,14 +631,58 @@ node_type(#xmlAttribute{}) -> attribute; node_type(#xmlElement{}) -> element; node_type(#xmlText{}) -> text; node_type(#xmlPI{}) -> processing_instruction; -node_type(#xmlNamespace{}) -> namespace; +node_type(#xmlNsNode{}) -> namespace; +node_type(#xmlComment{}) -> comment; node_type(#xmlDocument{}) -> root_node. %% "The namespace axis contains the namespace nodes of the context node; %% the axis will be empty unless the context node is an element." -%match_namespace(_Tok, _N, _Acc, _Context) -> - %% TODO: IMPLEMENT NAMESPACE AXIS -% erlang:fault(not_yet_implemented). +match_namespace(Tok, N, Acc, Context) -> + case N#xmlNode.type of + element -> + #xmlNode{parents = Ps, node = E} = N, + #xmlElement{name = Name, + namespace = NS, + parents = EPs, + pos = Pos} = E, + #xmlNamespace{default = Default, nodes = NSPairs} = NS, + ThisEPs = [{Name, Pos}|EPs], + ThisPs = [N|Ps], + Acc0 = + case Default of + D when D =:= []; D =:= '' -> + {[], 1}; + URI -> + DefaultNSNode = #xmlNsNode{parents = ThisEPs, + pos = 1, + prefix = [], + uri = URI}, + Node = #xmlNode{type = namespace, + node = DefaultNSNode, + parents = ThisPs}, + {[Node], 2} + end, + {Nodes, _I} = + lists:foldr( + fun ({Prefix, URI}, {AccX, I}) -> + NSNode = #xmlNsNode{parents = ThisEPs, + pos = I, + prefix = Prefix, + uri = URI}, + ThisN = #xmlNode{pos = I, + type = namespace, + node = NSNode, + parents = ThisPs}, + {[ThisN | AccX], I + 1} + end, Acc0, NSPairs), + lists:foldr( + fun (ThisN, AccX) -> + match_self(Tok, ThisN, AccX, Context) + end, Acc, Nodes); + _Other -> + %%[] + Acc + end. update_nodeset(Context = #xmlContext{axis_type = AxisType}, NodeSet) -> @@ -655,8 +703,15 @@ update_nodeset(Context = #xmlContext{axis_type = AxisType}, NodeSet) -> node_test(F, N, Context) when is_function(F) -> F(N, Context); +node_test(_Test, #xmlNode{type=attribute,node=#xmlAttribute{name=xmlns}}, + _Context) -> + false; +node_test(_Test, + #xmlNode{type=attribute,node=#xmlAttribute{nsinfo={"xmlns",_Local}}}, + _Context) -> + false; node_test({wildcard, _}, #xmlNode{type=ElAt}, _Context) - when ElAt==element; ElAt==attribute -> + when ElAt==element; ElAt==attribute; ElAt==namespace -> true; node_test({prefix_test, Prefix}, #xmlNode{node = N}, _Context) -> case N of @@ -720,6 +775,9 @@ node_test({name, {_Tag, Prefix, Local}}, [{_Tag, Prefix, Local}, write_node(NSNodes)]), false end; +node_test({name, {_Tag, [], Local}}, + #xmlNode{node = #xmlNsNode{prefix = Local}}, _Context) -> + true; node_test({node_type, NT}, #xmlNode{node = N}, _Context) -> case {NT, N} of {text, #xmlText{}} -> @@ -728,14 +786,18 @@ node_test({node_type, NT}, #xmlNode{node = N}, _Context) -> true; {attribute, #xmlAttribute{}} -> true; - {namespace, #xmlNamespace{}} -> + {namespace, #xmlNsNode{}} -> + true; + {comment, #xmlComment{}} -> + true; + {processing_instruction, #xmlPI{}} -> true; _ -> false end; -node_test({processing_instruction, {literal, _, Name}}, - #xmlNode{node = {processing_instruction, Name, _Data}}, _Context) -> - true; +node_test({processing_instruction, Name1}, + #xmlNode{node = #xmlPI{name = Name2}}, _Context) -> + Name1 == atom_to_list(Name2); node_test(_Other, _N, _Context) -> %io:format("node_test(~p, ~p) -> false.~n", [_Other, write_node(_N)]), false. diff --git a/lib/xmerl/src/xmerl_xpath_lib.erl b/lib/xmerl/src/xmerl_xpath_lib.erl index cfd0e36667..096f54ec30 100644 --- a/lib/xmerl/src/xmerl_xpath_lib.erl +++ b/lib/xmerl/src/xmerl_xpath_lib.erl @@ -49,5 +49,7 @@ primary_expr({function_call, F, Args}, C) -> %% here, we should look up the function in the context provided %% by the caller, but we haven't figured this out yet. exit({not_a_core_function, F}) - end. + end; +primary_expr(PrimExpr, _C) -> + exit({primary_expression, {not_implemented, PrimExpr}}). diff --git a/lib/xmerl/src/xmerl_xpath_parse.yrl b/lib/xmerl/src/xmerl_xpath_parse.yrl index 37576b9e61..f60cea0a2e 100644 --- a/lib/xmerl/src/xmerl_xpath_parse.yrl +++ b/lib/xmerl/src/xmerl_xpath_parse.yrl @@ -144,6 +144,7 @@ Expect 2. %% [7] 'NodeTest' -> 'NameTest' : '$1' . 'NodeTest' -> 'node_type' '(' ')' : {node_type, value('$1')} . +'NodeTest' -> 'processing-instruction' '(' ')' : {node_type, value('$1')} . 'NodeTest' -> 'processing-instruction' '(' 'literal' ')' : {processing_instruction, value('$3')} . diff --git a/lib/xmerl/src/xmerl_xpath_pred.erl b/lib/xmerl/src/xmerl_xpath_pred.erl index 451a09bee3..855b8599fe 100644 --- a/lib/xmerl/src/xmerl_xpath_pred.erl +++ b/lib/xmerl/src/xmerl_xpath_pred.erl @@ -337,6 +337,9 @@ local_name1([#xmlNode{type=element,node=El}|_]) -> local_name1([#xmlNode{type=attribute,node=Att}|_]) -> #xmlAttribute{name=Name,nsinfo=NSI} = Att, local_name2(Name,NSI); +local_name1([#xmlNode{type=namespace,node=N}|_]) -> + #xmlNsNode{prefix=Prefix} = N, + ?string(Prefix); local_name1([#xmlElement{name = Name, nsinfo = NSI}|_]) -> local_name2(Name,NSI). local_name2(Name, NSI) -> @@ -431,6 +434,9 @@ string_value(N=#xmlObj{}) -> string_value(A=#xmlNode{type=attribute}) -> #xmlAttribute{value=AttVal}=A#xmlNode.node, ?string(AttVal); +string_value(N=#xmlNode{type=namespace}) -> + #xmlNsNode{uri=URI}=N#xmlNode.node, + ?string(atom_to_list(URI)); string_value(El=#xmlNode{type=element}) -> #xmlElement{content=C} = El#xmlNode.node, TextValue = fun(#xmlText{value=T},_Fun) -> T; @@ -442,6 +448,9 @@ string_value(El=#xmlNode{type=element}) -> string_value(T=#xmlNode{type=text}) -> #xmlText{value=Txt} = T#xmlNode.node, ?string(Txt); +string_value(T=#xmlNode{type=comment}) -> + #xmlComment{value=Txt} = T#xmlNode.node, + ?string(Txt); string_value(infinity) -> ?string("Infinity"); string_value(neg_infinity) -> ?string("-Infinity"); string_value(A) when is_atom(A) -> diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index dfdc6138ef..ed0890f0d0 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -245,21 +245,27 @@ process_validate2({SE,_},Schema,Xml,Opts) -> S4 = validation_options(S3,Opts), validate3(Schema,Xml,S4). -validate3(Schema,Xml,S=#xsd_state{errors=[]}) -> - Ret = {_,S2} = - case catch validate_xml(Xml,S) of - {[XML2],[],Sx} -> - {XML2,Sx}; - {XML2,[],Sx} -> - {XML2,Sx}; - {_,UnValidated,Sx} -> - {Xml,acc_errs(Sx,{error_path(UnValidated,Xml#xmlElement.name),?MODULE, - {unvalidated_rest,UnValidated}})}; - _Err = {error,Reason} -> - {Xml,acc_errs(S,Reason)}; - {'EXIT',Reason} -> - {Xml,acc_errs(S,{error_path(Xml,Xml#xmlElement.name),?MODULE, - {undefined,{internal_error,Reason}}})} +validate3(Schema, Xml,S =#xsd_state{errors=[]}) -> + Ret = {_, S2} = + case catch validate_xml(Xml, S) of + _Err = {error, Reason} -> + {Xml, acc_errs(S, Reason)}; + {'EXIT', Reason} -> + {Xml, acc_errs(S, {error_path(Xml, Xml#xmlElement.name), ?MODULE, + {undefined, {internal_error, Reason}}})}; + {XML2, Rest, Sx} -> + case lists:dropwhile(fun(X) when is_record(X, xmlComment) -> true; (_) -> false end, Rest) of + [] -> + case XML2 of + [XML3] -> + {XML3,Sx}; + XML3 -> + {XML3,Sx} + end; + UnValidated -> + {Xml,acc_errs(Sx,{error_path(UnValidated,Xml#xmlElement.name),?MODULE, + {unvalidated_rest,UnValidated}})} + end end, save_to_file(S2,filename:rootname(Schema)++".tab2"), case S2#xsd_state.errors of @@ -1950,7 +1956,7 @@ fetch_external_schema(Path,S) when is_list(Path) -> {EXSD,S#xsd_state{schema_name=File}} end; {_,{string,String},_} -> %% this is for a user defined fetch fun that returns an xml document on string format. - ?debug("scanning string: ~p~n",[File]), + ?debug("scanning string: ~p~n",[String]), case xmerl_scan:string(String,S#xsd_state.xml_options) of {error,Reason} -> {error,acc_errs(S,{[],?MODULE,{parsing_external_schema_failed,Path,Reason}})}; @@ -2520,9 +2526,9 @@ check_element_type([],#schema_complex_type{name=_Name,block=_Bl,content=C}, {error,{error_path(Checked,undefined),?MODULE, {empty_content_not_allowed,C}}} end; -check_element_type(C,{anyType,_},_Env,_Block,S,_Checked) -> +check_element_type(C, {anyType, _}, _Env, _Block, S, _Checked) -> %% permitt anything - {C,[],S}; + {lists:reverse(C), [], S}; check_element_type(XML=[#xmlText{}|_],Type=#schema_simple_type{}, _Env,_Block,S,_Checked) -> @@ -2585,7 +2591,7 @@ check_element_type(XML=[XMLEl=#xmlElement{name=Name}|RestXML], S6 = check_form(ElName,Name,XMLEl, actual_form_value(CMEl#schema_element.form, S5#xsd_state.elementFormDefault), - S5), + S5), %Step into content of XML element. {Content,_,S7} = case @@ -2605,12 +2611,12 @@ check_element_type(XML=[XMLEl=#xmlElement{name=Name}|RestXML], RestXML, set_scope(S5#xsd_state.scope,set_num_el(S7,S6))}; true -> - {error,{error_path(XMLEl,Name),?MODULE, - {element_not_suitable_with_schema,ElName,S}}}; + {error,{error_path(XMLEl, Name), ?MODULE, + {element_not_suitable_with_schema, ElName, S}}}; _ when S#xsd_state.num_el >= Min -> %% it may be a match error or an optional element not %% present - {[],XML,S#xsd_state{num_el=0}}; + {[], XML, S#xsd_state{num_el=0}}; _ -> {error,{error_path(XMLEl,Name),?MODULE, {element_not_suitable_with_schema,ElName,CMName,CMEl,S}}} @@ -2645,7 +2651,7 @@ check_element_type(XML=[#xmlElement{}|_Rest], check_element_type(XML=[E=#xmlElement{name=Name}|Rest], Any={any,{Namespace,_Occ={Min,_},ProcessorContents}},Env, _Block,S,_Checked) -> - ?debug("check any: {any,{~p,~p,~p}}~n",[Namespace,Occ,ProcessorContents]), + ?debug("check any: {any,{~p,~p,~p}}~n",[Namespace,_Occ,ProcessorContents]), %% ProcessorContents any of lax | strict | skip %% lax: may validate if schema is found %% strict: must validate @@ -2710,8 +2716,11 @@ check_element_type([],CM,_Env,_Block,S,Checked) -> {error,{error_path(Checked,undefined),?MODULE, {empty_content_not_allowed,CM}}} end; +check_element_type([C = #xmlComment{} |Rest],CM,Env,Block,S,Checked) -> + check_element_type(Rest,CM,Env,Block,S,[C |Checked]); check_element_type(XML,CM,_Env,_Block,S,_Checked) -> {error,{error_path(XML,undefined),?MODULE,{match_failure,XML,CM,S}}}. + %% single xml content object and single schema object check_text_type(XML=[#xmlText{}|_],optional_text,S) -> % {XMLTxt,optional_text}; @@ -2730,7 +2739,7 @@ check_text_type([XMLTxt=#xmlText{}|_],CMEl,_S) -> {cannot_contain_text,XMLTxt,CMEl}}}. split_xmlText(XML) -> - splitwith(fun(#xmlText{}) -> true;(_) -> false end,XML). + splitwith(fun(#xmlText{}) -> true;(#xmlComment{}) -> true;(_) -> false end,XML). %% Sequence check_sequence([T=#xmlText{}|Rest],Els,Occ,Env,S,Checked) -> @@ -2773,6 +2782,8 @@ check_sequence(Seq=[_InstEl=#xmlElement{}|_],[El|Els],Occ={_Min,_Max},Env,S,Chec count_num_el(set_num_el(S3,S2)), Ret++Checked) end; +check_sequence([C = #xmlComment{} |Rest], Els, Occ, Env, S, Checked) -> + check_sequence(Rest,Els,Occ,Env,S,[C |Checked]); check_sequence(Rest,[],_Occ,_Env,S,Checked) -> {Checked,Rest,set_num_el(S,0)}; check_sequence([],Els,_Occ,_Env,S,Checked) -> @@ -2869,6 +2880,8 @@ check_all(XML=[E=#xmlElement{name=Name}|RestXML],CM,Occ,Env,S, {element_not_in_all,ElName,E,CM}}, check_all(RestXML,CM,Occ,Env,acc_errs(S,Err),[E|Checked],PrevXML) end; +check_all([C=#xmlComment{} |RestXML], CM, Occ, Env, S, Checked, XML) -> + check_all(RestXML, CM, Occ, Env, S, [C |Checked], XML); check_all(XML,[],_,_,S,Checked,_) -> {Checked,XML,S}; check_all([],CM,_Occ,_,S,Checked,_PrevXML) -> @@ -2920,7 +2933,7 @@ check_target_namespace(XMLEl,S) -> schemaLocations(El=#xmlElement{attributes=Atts},S) -> Pred = fun(#xmlAttribute{name=schemaLocation}) -> false; - (#xmlAttribute{namespace={_,"schemaLocation"}}) -> false; + (#xmlAttribute{nsinfo={_,"schemaLocation"}}) -> false; (_) -> true end, case lists:dropwhile(Pred,Atts) of diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl index 94c38d4d48..55b6d1844c 100644 --- a/lib/xmerl/test/xmerl_SUITE.erl +++ b/lib/xmerl/test/xmerl_SUITE.erl @@ -58,7 +58,7 @@ groups() -> {ticket_tests, [], [ticket_5998, ticket_7211, ticket_7214, ticket_7430, ticket_6873, ticket_7496, ticket_8156, ticket_8697, - ticket_9411, ticket_9457]}, + ticket_9411, ticket_9457, ticket_9664_schema, ticket_9664_dtd]}, {app_test, [], [{xmerl_app_test, all}]}, {appup_test, [], [{xmerl_appup_test, all}]}]. @@ -284,7 +284,7 @@ export(Config) -> ?line {E,_} = xmerl_scan:file(TestFile), ?line Exported = xmerl:export([E],xmerl_xml,[{prolog,Prolog}]), B = list_to_binary(Exported++"\n"), - ?line {ok,B} = file:read_file(TestFile), + ?line {ok, B} = file:read_file(TestFile), ok. %%---------------------------------------------------------------------- @@ -609,6 +609,38 @@ ticket_9457_cont(Continue, Exception, GlobalState) -> Exception(GlobalState) end. + +ticket_9664_schema(suite) -> []; +ticket_9664_schema(doc) -> + ["Test that comments are handled correct whith"]; +ticket_9664_schema(Config) -> + + ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc, + "ticket_9664_schema.xml"]),[]), + ?line {ok, S} = xmerl_xsd:process_schema(filename:join([?config(data_dir, Config), misc, + "motorcycles.xsd"])), + ?line {E1, _} = xmerl_xsd:validate(E, S), + + ?line {E1,_} = xmerl_xsd:process_validate(filename:join([?config(data_dir,Config), misc, + "motorcycles.xsd"]),E,[]), + + ?line {E1,_} = xmerl_scan:file(filename:join([?config(data_dir,Config), misc, + "ticket_9664_schema.xml"]), + [{schemaLocation, [{"mc", "motorcycles.xsd"}]}, + {validation, schema}]), + ok. + +ticket_9664_dtd(suite) -> []; +ticket_9664_dtd(doc) -> + ["Test that comments are handled correct whith"]; +ticket_9664_dtd(Config) -> + ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc, + "ticket_9664_dtd.xml"]),[]), + ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc, + "ticket_9664_dtd.xml"]),[{validation, true}]), + ok. + + %%====================================================================== %% Support Functions %%====================================================================== diff --git a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz Binary files differindex fef7431845..ffc1d327a5 100644 --- a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz +++ b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz diff --git a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl index 850b7f8135..7b6f1e95b3 100644 --- a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl +++ b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl @@ -210,7 +210,7 @@ ticket_7496() -> ?line {Doc3,_} = xmerl_scan:file("documentRoot.xml"), ?line ok = Test(Doc3,"//child",[child,child,child]), ?line ok = Test(Doc3,"//child[@name='beta']",[child]), - ?line [{xmlAttribute,id,[],[],[],[],1,[],"2",false}] = + ?line [{xmlAttribute,id,[],[],[],_,1,[],"2",false}] = xmerl_xpath:string("/documentRoot/parent/child[@name='beta']/@id",Doc3), ?line ok = Test(Doc3,"/documentRoot/parent/child|/documentRoot/parent/pet", [child,child,child,pet,pet]), diff --git a/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd b/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd index 057344cde8..057344cde8 100755..100644 --- a/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd +++ b/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 82df8fdeef..de47e3418b 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.2.10 +XMERL_VSN = 1.3 diff --git a/lib/xmerl/xmerl.pub b/lib/xmerl/xmerl.pub index 29a81bbde2..29a81bbde2 100755..100644 --- a/lib/xmerl/xmerl.pub +++ b/lib/xmerl/xmerl.pub |