aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore59
-rw-r--r--Makefile.in5
-rw-r--r--erts/Makefile.in8
-rw-r--r--erts/emulator/beam/erl_process.c28
-rwxr-xr-x[-rw-r--r--]erts/emulator/drivers/win32/win_efile.c131
-rw-r--r--erts/emulator/test/Makefile1
-rw-r--r--erts/emulator/test/mtx_SUITE.erl473
-rw-r--r--erts/emulator/test/mtx_SUITE_data/Makefile.src30
-rw-r--r--erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c692
-rw-r--r--erts/emulator/test/port_SUITE.erl19
-rw-r--r--erts/etc/common/Makefile.in14
-rw-r--r--erts/etc/common/ct_run.c (renamed from erts/etc/common/run_test.c)28
-rw-r--r--erts/etc/unix/Install.src5
-rw-r--r--erts/etc/unix/format_man_pages31
-rw-r--r--erts/etc/win32/Install.c16
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ld.sh2
-rw-r--r--erts/include/internal/ethr_mutex.h145
-rw-r--r--erts/include/internal/i386/atomic.h49
-rw-r--r--erts/include/internal/sparc32/atomic.h35
-rw-r--r--erts/lib_src/common/ethr_mutex.c631
-rw-r--r--erts/test/ethread_SUITE.erl10
-rw-r--r--lib/common_test/doc/src/Makefile2
-rw-r--r--lib/common_test/doc/src/config_file_chapter.xml2
-rw-r--r--lib/common_test/doc/src/cover_chapter.xml4
-rw-r--r--lib/common_test/doc/src/ct_junit_report.xml109
-rw-r--r--lib/common_test/doc/src/ct_master_chapter.xml2
-rw-r--r--lib/common_test/doc/src/ct_run.xml (renamed from lib/common_test/doc/src/run_test.xml)34
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml6
-rw-r--r--lib/common_test/doc/src/install_chapter.xml16
-rw-r--r--lib/common_test/doc/src/ref_man.xml2
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml94
-rw-r--r--lib/common_test/doc/src/test_structure_chapter.xml2
-rw-r--r--lib/common_test/src/ct.erl8
-rw-r--r--lib/common_test/src/ct_run.erl22
-rw-r--r--lib/compiler/doc/src/compile.xml10
-rw-r--r--lib/debugger/test/int_eval_SUITE.erl5
-rw-r--r--lib/docbuilder/src/docb_main.erl29
-rw-r--r--lib/erl_docgen/Makefile19
-rw-r--r--lib/erl_docgen/ebin/.gitignore0
-rw-r--r--lib/erl_docgen/priv/bin/specs_gen.escript129
-rwxr-xr-xlib/erl_docgen/priv/bin/xref_mod_app.escript107
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd7
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd2
-rw-r--r--lib/erl_docgen/priv/dtd_man_entities/xhtml-lat1.ent128
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl626
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl345
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf.xsl486
-rw-r--r--lib/erl_docgen/src/Makefile96
-rw-r--r--lib/erl_docgen/src/erl_docgen.app.src12
-rw-r--r--lib/erl_docgen/src/erl_docgen.appup.src1
-rw-r--r--lib/erl_docgen/src/otp_specs.erl701
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c18
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl2
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c20
-rw-r--r--lib/et/src/et_selector.erl4
-rw-r--r--lib/eunit/doc/src/Makefile2
-rw-r--r--lib/eunit/src/eunit.erl2
-rw-r--r--lib/eunit/src/eunit_surefire.erl2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl23
-rw-r--r--lib/inets/doc/src/ftp.xml2
-rw-r--r--lib/inets/doc/src/http_client.xml4
-rw-r--r--lib/inets/doc/src/httpc.xml13
-rw-r--r--lib/inets/doc/src/httpd.xml12
-rw-r--r--lib/inets/include/httpd.hrl41
-rw-r--r--lib/inets/src/http_client/Makefile1
-rw-r--r--lib/inets/src/http_client/httpc.erl50
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl119
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl6
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl9
-rw-r--r--lib/inets/src/http_lib/Makefile3
-rw-r--r--lib/inets/src/http_lib/http_transport.erl9
-rw-r--r--lib/inets/src/http_lib/http_uri.erl (renamed from lib/inets/src/http_client/http_uri.erl)50
-rw-r--r--lib/inets/src/http_server/Makefile8
-rw-r--r--lib/inets/src/http_server/httpd.erl5
-rw-r--r--lib/inets/src/http_server/httpd.hrl82
-rw-r--r--lib/inets/src/http_server/httpd_acceptor.erl1
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl2
-rw-r--r--lib/inets/src/http_server/httpd_file.erl12
-rw-r--r--lib/inets/src/http_server/httpd_internal.hrl45
-rw-r--r--lib/inets/src/http_server/httpd_request.erl4
-rw-r--r--lib/inets/src/http_server/httpd_script_env.erl3
-rw-r--r--lib/inets/src/http_server/httpd_sup.erl2
-rw-r--r--lib/inets/src/http_server/httpd_util.erl55
-rw-r--r--lib/inets/src/http_server/mod_actions.erl3
-rw-r--r--lib/inets/src/http_server/mod_alias.erl1
-rw-r--r--lib/inets/src/http_server/mod_auth.erl3
-rw-r--r--lib/inets/src/http_server/mod_auth_dets.erl3
-rw-r--r--lib/inets/src/http_server/mod_auth_plain.erl4
-rw-r--r--lib/inets/src/http_server/mod_auth_server.erl3
-rw-r--r--lib/inets/src/http_server/mod_cgi.erl1
-rw-r--r--lib/inets/src/http_server/mod_dir.erl8
-rw-r--r--lib/inets/src/http_server/mod_disk_log.erl4
-rw-r--r--lib/inets/src/http_server/mod_esi.erl1
-rw-r--r--lib/inets/src/http_server/mod_get.erl4
-rw-r--r--lib/inets/src/http_server/mod_head.erl2
-rw-r--r--lib/inets/src/http_server/mod_htaccess.erl3
-rw-r--r--lib/inets/src/http_server/mod_include.erl7
-rw-r--r--lib/inets/src/http_server/mod_log.erl3
-rw-r--r--lib/inets/src/http_server/mod_range.erl4
-rw-r--r--lib/inets/src/http_server/mod_responsecontrol.erl3
-rw-r--r--lib/inets/src/http_server/mod_security.erl3
-rw-r--r--lib/inets/src/http_server/mod_security_server.erl3
-rw-r--r--lib/inets/src/http_server/mod_trace.erl2
-rw-r--r--lib/inets/src/inets_app/inets.appup.src10
-rw-r--r--lib/inets/test/Makefile24
-rw-r--r--lib/inets/test/httpc_SUITE.erl45
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl36
-rw-r--r--lib/inets/test/inets_appup_test.erl5
-rw-r--r--lib/inets/vsn.mk21
-rw-r--r--lib/kernel/src/error_handler.erl5
-rw-r--r--lib/kernel/test/code_SUITE.erl97
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl6
-rw-r--r--lib/mnesia/src/mnesia.appup.src6
-rw-r--r--lib/mnesia/src/mnesia_dumper.erl4
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/odbc/src/odbc.appup.src9
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/public_key/src/pubkey_cert.erl2
-rw-r--r--lib/public_key/src/public_key.appup.src12
-rw-r--r--lib/public_key/src/public_key.erl25
-rw-r--r--lib/public_key/test/public_key_SUITE.erl4
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/ssl/doc/src/ssl.xml12
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/ssl_certificate.erl1
-rw-r--r--lib/ssl/src/ssl_cipher.erl1
-rw-r--r--lib/ssl/src/ssl_connection.erl1
-rw-r--r--lib/ssl/src/ssl_handshake.erl1
-rw-r--r--lib/ssl/src/ssl_handshake.hrl7
-rw-r--r--lib/ssl/src/ssl_internal.hrl40
-rw-r--r--lib/ssl/src/ssl_record.erl1
-rw-r--r--lib/ssl/src/ssl_ssl3.erl1
-rw-r--r--lib/ssl/src/ssl_tls1.erl1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl5
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl3
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/dets.xml4
-rw-r--r--lib/stdlib/src/dets.hrl4
-rw-r--r--lib/stdlib/test/ets_SUITE.erl21
-rw-r--r--lib/tools/src/eprof.erl9
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_base.erlsrc41
-rw-r--r--lib/xmerl/src/xmerl_scan.erl2
-rw-r--r--lib/xmerl/src/xmerl_xpath.erl4
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl3
-rw-r--r--make/otp.mk.in29
-rw-r--r--make/otp_release_targets.mk44
147 files changed, 5462 insertions, 1191 deletions
diff --git a/.gitignore b/.gitignore
index 559d6b8898..d67116d6e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,65 @@ powerpc-unknown-linux-gnu
# Mac OS X
a.out.dSYM/
+# Windows
+*.pdb
+tcltk85_win32_bin.tar.gz
+erts/autoconf/win32.config.cache
+erts/emulator/obj/
+erts/emulator/pcre/obj/
+erts/emulator/pcre/win32/
+erts/emulator/win32/
+erts/emulator/zlib/obj/
+erts/emulator/zlib/win32/
+erts/epmd/src/win32/
+erts/etc/common/Install.ini
+erts/etc/common/win32/
+erts/etc/win32/cygwin_tools/vc/coffix.exe
+erts/include/internal/win32/
+erts/include/win32/
+erts/lib/internal/win32/
+erts/lib/win32/
+erts/lib_src/obj/
+erts/lib_src/win32/
+erts/obj/win32/
+erts/win32/
+erts/etc/win32/nsis/erlang.nsh
+lib/asn1/priv/lib/
+lib/asn1/priv/obj/
+lib/common_test/priv/win32/
+lib/crypto/c_src/win32/
+lib/crypto/priv/lib/
+lib/crypto/priv/obj/
+lib/erl_interface/obj.md/
+lib/erl_interface/obj.mdd/
+lib/erl_interface/src/win32/
+lib/gs/priv/tcl/
+lib/gs/tcl/binaries/
+lib/ic/c_src/win32/
+lib/ic/priv/lib/win32/
+lib/ic/priv/obj/win32/
+lib/megaco/src/flex/win32/
+lib/odbc/c_src/win32/
+lib/odbc/priv/bin/odbcserver.exe
+lib/odbc/priv/obj/win32/odbcserver.o
+lib/orber/c_src/win32/
+lib/os_mon/c_src/win32/
+lib/os_mon/priv/bin/win32/
+lib/os_mon/priv/obj/win32/
+lib/runtime_tools/c_src/win32/
+lib/runtime_tools/priv/lib/
+lib/runtime_tools/priv/obj/
+lib/ssl/c_src/win32/
+lib/ssl/priv/bin/win32/
+lib/ssl/priv/obj/win32/
+lib/tools/bin/win32/
+lib/tools/c_src/win32/
+lib/tools/obj/win32/
+lib/wx/c_src/win32/
+lib/wx/priv/win32/
+lib/wx/win32/
+make/win32/
+
# Anchored from $ERL_TOP
/bin
/config.log
diff --git a/Makefile.in b/Makefile.in
index 4b6e2e1190..ca92bf604d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -393,7 +393,7 @@ endif
# ---------------------------------------------------------------
# Target only used when building commercial ERTS patches
# ---------------------------------------------------------------
-release_docs docs:
+release_docs docs: mod2app
ifeq ($(OTP_SMALL_BUILD),true)
cd $(ERL_TOP)/lib && \
ERL_TOP=$(ERL_TOP) $(MAKE) TESTROOT=$(RELEASE_ROOT) $@
@@ -408,6 +408,9 @@ endif
cd $(ERL_TOP)/system/doc && \
ERL_TOP=$(ERL_TOP) $(MAKE) TESTROOT=$(RELEASE_ROOT) $@
+mod2app:
+ $(ERL_TOP)/lib/erl_docgen/priv/bin/xref_mod_app.escript -topdir $(ERL_TOP) -outfile $(ERL_TOP)/make/$(TARGET)/mod2app.xml
+
# ----------------------------------------------------------------------
ERLANG_EARS=$(BOOTSTRAP_ROOT)/bootstrap/erts
ELINK=$(BOOTSTRAP_ROOT)/bootstrap/erts/bin/elink
diff --git a/erts/Makefile.in b/erts/Makefile.in
index dc8edcd928..2e63fc469e 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile.in
@@ -87,17 +87,20 @@ endif
# in the same directory...
local_setup:
@cd start_scripts && $(MAKE)
+ @echo `ls $(ERL_TOP)/bin/`
@rm -f $(ERL_TOP)/bin/erl $(ERL_TOP)/bin/erlc $(ERL_TOP)/bin/cerl \
$(ERL_TOP)/bin/erl.exe $(ERL_TOP)/bin/erlc.exe \
$(ERL_TOP)/bin/escript $(ERL_TOP)/bin/escript.exe \
$(ERL_TOP)/bin/dialyzer $(ERL_TOP)/bin/dialyzer.exe \
$(ERL_TOP)/bin/typer $(ERL_TOP)/bin/typer.exe \
$(ERL_TOP)/bin/run_test $(ERL_TOP)/bin/run_test.exe \
+ $(ERL_TOP)/bin/ct_run $(ERL_TOP)/bin/ct_run.exe \
$(ERL_TOP)/bin/start*.boot $(ERL_TOP)/bin/start*.script
@if [ "X$(TARGET)" = "Xwin32" ]; then \
cp $(ERL_TOP)/bin/$(TARGET)/dialyzer.exe $(ERL_TOP)/bin/dialyzer.exe; \
cp $(ERL_TOP)/bin/$(TARGET)/typer.exe $(ERL_TOP)/bin/typer.exe; \
- cp $(ERL_TOP)/bin/$(TARGET)/run_test.exe $(ERL_TOP)/bin/run_test.exe; \
+ cp $(ERL_TOP)/bin/$(TARGET)/ct_run.exe $(ERL_TOP)/bin/ct_run.exe; \
+ cp $(ERL_TOP)/bin/$(TARGET)/ct_run.exe $(ERL_TOP)/bin/run_test.exe; \
cp $(ERL_TOP)/bin/$(TARGET)/erlc.exe $(ERL_TOP)/bin/erlc.exe; \
cp $(ERL_TOP)/bin/$(TARGET)/erl.exe $(ERL_TOP)/bin/erl.exe; \
cp $(ERL_TOP)/bin/$(TARGET)/werl.exe $(ERL_TOP)/bin/werl.exe; \
@@ -117,7 +120,8 @@ local_setup:
$(ERL_TOP)/erts/etc/unix/cerl.src > $(ERL_TOP)/bin/cerl; \
cp $(ERL_TOP)/bin/$(TARGET)/dialyzer $(ERL_TOP)/bin/dialyzer; \
cp $(ERL_TOP)/bin/$(TARGET)/typer $(ERL_TOP)/bin/typer; \
- cp $(ERL_TOP)/bin/$(TARGET)/run_test $(ERL_TOP)/bin/run_test; \
+ cp $(ERL_TOP)/bin/$(TARGET)/ct_run $(ERL_TOP)/bin/ct_run; \
+ ln -s $(ERL_TOP)/bin/ct_run $(ERL_TOP)/bin/run_test; \
cp $(ERL_TOP)/bin/$(TARGET)/erlc $(ERL_TOP)/bin/erlc; \
cp $(ERL_TOP)/bin/$(TARGET)/escript $(ERL_TOP)/bin/escript; \
chmod 755 $(ERL_TOP)/bin/erl $(ERL_TOP)/bin/erlc \
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index f252c2cbe2..fc950af8ce 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -1842,6 +1842,9 @@ do { \
static void
check_balance(ErtsRunQueue *c_rq)
{
+#if ERTS_MAX_PROCESSES >= (1 << 27)
+# error check_balance() assumes ERTS_MAX_PROCESS < (1 << 27)
+#endif
ErtsRunQueueBalance avg = {0};
Sint64 scheds_reds, full_scheds_reds;
int forced, active, current_active, oowc, half_full_scheds, full_scheds,
@@ -1965,12 +1968,14 @@ check_balance(ErtsRunQueue *c_rq)
run_queue_info[qix].prio[pix].avail = 0;
}
else {
- int xreds = 0;
- int procreds = treds;
- procreds -= run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds;
+ Sint64 xreds = 0;
+ Sint64 procreds = treds;
+ procreds -=
+ ((Sint64)
+ run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds);
for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
- int av;
+ Sint64 av;
if (xreds == 0)
av = 100;
@@ -1981,9 +1986,10 @@ check_balance(ErtsRunQueue *c_rq)
if (av == 0)
av = 1;
}
- run_queue_info[qix].prio[pix].avail = av;
+ run_queue_info[qix].prio[pix].avail = (int) av;
+ ASSERT(run_queue_info[qix].prio[pix].avail >= 0);
if (pix < PRIORITY_NORMAL) /* ie., max or high */
- xreds += run_queue_info[qix].prio[pix].reds;
+ xreds += (Sint64) run_queue_info[qix].prio[pix].reds;
}
run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].avail = 100;
}
@@ -2088,7 +2094,8 @@ check_balance(ErtsRunQueue *c_rq)
if (max_len != 0) {
int avail = avg.prio[pix].avail;
if (avail != 0) {
- max_len = ((100*max_len - 1) / avail) + 1;
+ max_len = (int) ((100*((Sint64) max_len) - 1)
+ / ((Sint64) avail)) + 1;
avg.prio[pix].max_len = max_len;
ASSERT(max_len >= 0);
}
@@ -2105,9 +2112,10 @@ check_balance(ErtsRunQueue *c_rq)
|| run_queue_info[qix].prio[pix].avail == 0)
limit = 0;
else
- limit = (((avg.prio[pix].max_len
- * run_queue_info[qix].prio[pix].avail) - 1)
- / 100 + 1);
+ limit = (int) (((((Sint64) avg.prio[pix].max_len)
+ * ((Sint64) run_queue_info[qix].prio[pix].avail))
+ - 1)
+ / 100 + 1);
run_queue_info[qix].prio[pix].migration_limit = limit;
}
}
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 04bd1139f5..6de08e2fa6 100644..100755
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -862,6 +862,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
findbuf.nFileSizeLow = 0;
findbuf.cFileName[0] = '\0';
+ pInfo->links = 1;
pInfo->modifyTime.year = 1980;
pInfo->modifyTime.month = 1;
pInfo->modifyTime.day = 1;
@@ -874,6 +875,33 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
SYSTEMTIME SystemTime;
FILETIME LocalFTime;
+ /*first check if we are a symlink */
+ if (!info_for_link && (findbuf.dwFileAttributes &
+ FILE_ATTRIBUTE_REPARSE_POINT)){
+ /*
+ * given that we know this is a symlink,
+ we should be able to find its target */
+ char target_name[256];
+ if (efile_readlink(errInfo, name, target_name,256) == 1) {
+ return efile_fileinfo(errInfo, pInfo,
+ target_name, info_for_link);
+ }
+ }
+
+#if 0
+ /* number of links: */
+ {
+ HANDLE handle; /* Handle returned by CreateFile() */
+ BY_HANDLE_FILE_INFORMATION fileInfo; /* from CreateFile() */
+ if (handle = CreateFile(name, GENERIC_READ, 0,NULL,
+ OPEN_EXISTING, 0, NULL)) {
+ GetFileInformationByHandle(handle, &fileInfo);
+ pInfo->links = fileInfo.nNumberOfLinks;
+ CloseHandle(handle);
+ }
+ }
+#endif
+
#define GET_TIME(dst, src) \
if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \
!FileTimeToSystemTime(&LocalFTime, &SystemTime)) { \
@@ -908,7 +936,10 @@ if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \
pInfo->size_low = findbuf.nFileSizeLow;
pInfo->size_high = findbuf.nFileSizeHigh;
- if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ if (info_for_link && (findbuf.dwFileAttributes &
+ FILE_ATTRIBUTE_REPARSE_POINT))
+ pInfo->type = FT_SYMLINK;
+ else if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
pInfo->type = FT_DIRECTORY;
else
pInfo->type = FT_REGULAR;
@@ -919,7 +950,6 @@ if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \
pInfo->access = FA_READ|FA_WRITE;
pInfo->mode = dos_to_posix_mode(findbuf.dwFileAttributes, name);
- pInfo->links = 1;
pInfo->major_device = drive;
pInfo->minor_device = 0;
pInfo->inode = 0;
@@ -1082,12 +1112,17 @@ char* buf; /* Buffer to write. */
size_t count; /* Number of bytes to write. */
{
DWORD written; /* Bytes written in last operation. */
+ OVERLAPPED overlapped;
+ OVERLAPPED* pOverlapped = NULL;
if (flags & EFILE_MODE_APPEND) {
- (void) SetFilePointer((HANDLE) fd, 0, NULL, FILE_END);
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.Offset = 0xffffffff;
+ overlapped.OffsetHigh = 0xffffffff;
+ pOverlapped = &overlapped;
}
while (count > 0) {
- if (!WriteFile((HANDLE) fd, buf, count, &written, NULL))
+ if (!WriteFile((HANDLE) fd, buf, count, &written, pOverlapped))
return set_error(errInfo);
buf += written;
count -= written;
@@ -1107,11 +1142,16 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
size_t size) /* Number of bytes to write */
{
int cnt; /* Buffers so far written */
+ OVERLAPPED overlapped;
+ OVERLAPPED* pOverlapped = NULL;
ASSERT(iovcnt >= 0);
if (flags & EFILE_MODE_APPEND) {
- (void) SetFilePointer((HANDLE) fd, 0, NULL, FILE_END);
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.Offset = 0xffffffff;
+ overlapped.OffsetHigh = 0xffffffff;
+ pOverlapped = &overlapped;
}
for (cnt = 0; cnt < iovcnt; cnt++) {
if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
@@ -1123,7 +1163,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
iov[cnt].iov_base + p,
iov[cnt].iov_len - p,
&w,
- NULL))
+ pOverlapped))
return set_error(errInfo);
}
}
@@ -1343,6 +1383,48 @@ dos_to_posix_mode(int attr, const char *name)
int
efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
{
+ /*
+ * load dll and see if we have CreateSymbolicLink at runtime:
+ * (Vista only)
+ */
+ HINSTANCE hModule = NULL;
+ if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
+ typedef DWORD (WINAPI * GETFINALPATHNAMEBYHANDLEPTR)(
+ HANDLE hFile,
+ LPCSTR lpFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+ GETFINALPATHNAMEBYHANDLEPTR pGetFinalPathNameByHandle =
+ (GETFINALPATHNAMEBYHANDLEPTR)GetProcAddress(hModule, "GetFinalPathNameByHandleA");
+
+ if (pGetFinalPathNameByHandle == NULL) {
+ FreeLibrary(hModule);
+ } else {
+ /* first check if file is a symlink; {error, einval} otherwise */
+ DWORD fileAttributes = GetFileAttributes(name);
+ if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ BOOLEAN success = 0;
+ HANDLE h = CreateFile(name, GENERIC_READ, 0,NULL, OPEN_EXISTING, 0, NULL);
+ if(h != INVALID_HANDLE_VALUE) {
+ success = pGetFinalPathNameByHandle(h, buffer, size,0);
+ /* GetFinalPathNameByHandle prepends path with "\\?\": */
+ sprintf(buffer, buffer+4);
+ CloseHandle(h);
+ }
+ FreeLibrary(hModule);
+ if (success) {
+ return 1;
+ } else {
+ return set_error(errInfo);
+ }
+ } else {
+ FreeLibrary(hModule);
+ errno = EINVAL;
+ return check_error(-1, errInfo);
+ }
+ }
+ }
errno = ENOTSUP;
return check_error(-1, errInfo);
}
@@ -1427,13 +1509,46 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
int
efile_link(Efile_error* errInfo, char* old, char* new)
{
- errno = ENOTSUP;
- return check_error(-1, errInfo);
+ if(!CreateHardLink(new, old, NULL)) {
+ return set_error(errInfo);
+ }
+ return 1;
}
int
efile_symlink(Efile_error* errInfo, char* old, char* new)
{
+ /*
+ * Load dll and see if we have CreateSymbolicLink at runtime:
+ * (Vista only)
+ */
+ HINSTANCE hModule = NULL;
+ if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
+ typedef BOOLEAN (WINAPI * CREATESYMBOLICLINKFUNCPTR) (
+ LPCSTR lpSymlinkFileName,
+ LPCSTR lpTargetFileName,
+ DWORD dwFlags);
+
+ CREATESYMBOLICLINKFUNCPTR pCreateSymbolicLink =
+ (CREATESYMBOLICLINKFUNCPTR) GetProcAddress(hModule,
+ "CreateSymbolicLinkA");
+ /* A for MBCS, W for UNICODE... char* above implies 'A'! */
+ if (pCreateSymbolicLink != NULL) {
+ DWORD attr = GetFileAttributes(old);
+ int flag = (attr != INVALID_FILE_ATTRIBUTES &&
+ attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+ /* SYMBOLIC_LINK_FLAG_DIRECTORY = 1 */
+ BOOLEAN success = pCreateSymbolicLink(new, old, flag);
+ FreeLibrary(hModule);
+
+ if (success) {
+ return 1;
+ } else {
+ return set_error(errInfo);
+ }
+ } else
+ FreeLibrary(hModule);
+ }
errno = ENOTSUP;
return check_error(-1, errInfo);
}
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index a4c02da626..7259e1b84d 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -83,6 +83,7 @@ MODULES= \
receive_SUITE \
ref_SUITE \
register_SUITE \
+ mtx_SUITE \
save_calls_SUITE \
send_term_SUITE \
sensitive_SUITE \
diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl
new file mode 100644
index 0000000000..ae77fe4d89
--- /dev/null
+++ b/erts/emulator/test/mtx_SUITE.erl
@@ -0,0 +1,473 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+%%
+%% Stress tests of rwmutex implementation.
+%%
+%% Author: Rickard Green
+%%
+-module(mtx_SUITE).
+
+%%-define(line_trace,true).
+
+-include("test_server.hrl").
+
+-export([all/1, init_per_suite/1, end_per_suite/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([long_rwlock/1,
+ hammer_ets_rwlock/1,
+ hammer_rwlock/1,
+ hammer_rwlock_check/1,
+ hammer_tryrwlock/1,
+ hammer_tryrwlock_check/1,
+ hammer_sched_long_rwlock/1,
+ hammer_sched_long_rwlock_check/1,
+ hammer_sched_long_freqread_rwlock/1,
+ hammer_sched_long_freqread_rwlock_check/1,
+ hammer_sched_long_tryrwlock/1,
+ hammer_sched_long_tryrwlock_check/1,
+ hammer_sched_long_freqread_tryrwlock/1,
+ hammer_sched_long_freqread_tryrwlock_check/1,
+ hammer_sched_rwlock/1,
+ hammer_sched_rwlock_check/1,
+ hammer_sched_freqread_rwlock/1,
+ hammer_sched_freqread_rwlock_check/1,
+ hammer_sched_tryrwlock/1,
+ hammer_sched_tryrwlock_check/1,
+ hammer_sched_freqread_tryrwlock/1,
+ hammer_sched_freqread_tryrwlock_check/1]).
+
+init_per_suite(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Lib = filename:join([DataDir, atom_to_list(?MODULE)]),
+ ok = erlang:load_nif(Lib, none),
+ Config.
+
+end_per_suite(Config) when is_list(Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = ?t:timetrap(?t:minutes(15)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog).
+
+all(suite) ->
+ [
+ long_rwlock,
+ hammer_rwlock_check,
+ hammer_rwlock,
+ hammer_tryrwlock_check,
+ hammer_tryrwlock,
+ hammer_ets_rwlock,
+ hammer_sched_long_rwlock_check,
+ hammer_sched_long_rwlock,
+ hammer_sched_long_freqread_rwlock_check,
+ hammer_sched_long_freqread_rwlock,
+ hammer_sched_long_tryrwlock_check,
+ hammer_sched_long_tryrwlock,
+ hammer_sched_long_freqread_tryrwlock_check,
+ hammer_sched_long_freqread_tryrwlock,
+ hammer_sched_rwlock_check,
+ hammer_sched_rwlock,
+ hammer_sched_freqread_rwlock_check,
+ hammer_sched_freqread_rwlock,
+ hammer_sched_tryrwlock_check,
+ hammer_sched_tryrwlock,
+ hammer_sched_freqread_tryrwlock_check,
+ hammer_sched_freqread_tryrwlock
+ ].
+
+long_rwlock(Config) when is_list(Config) ->
+ statistics(runtime),
+ LLRes = long_rw_test(),
+ {_, RunTime} = statistics(runtime),
+ %% A very short run time is expected, since
+ %% threads in the test mostly wait
+ ?t:format("RunTime=~p~n", [RunTime]),
+ ?line true = RunTime < 100,
+ ?line RunTimeStr = "Run-time during test was "++integer_to_list(RunTime)++" ms.",
+ case LLRes of
+ ok ->
+ {comment, RunTimeStr};
+ {comment, Comment} ->
+ {comment, Comment ++ " " ++ RunTimeStr}
+ end.
+
+hammer_rwlock(Config) when is_list(Config) ->
+ hammer_rw_test(false).
+
+hammer_rwlock_check(Config) when is_list(Config) ->
+ hammer_rw_test(true).
+
+hammer_tryrwlock(Config) when is_list(Config) ->
+ hammer_tryrw_test(false).
+
+hammer_tryrwlock_check(Config) when is_list(Config) ->
+ hammer_tryrw_test(true).
+
+hammer_sched_rwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, false, true, 0, 0).
+
+hammer_sched_rwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, true, true, 0, 0).
+
+hammer_sched_freqread_rwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, false, true, 0, 0).
+
+hammer_sched_freqread_rwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, true, true, 0, 0).
+
+hammer_sched_tryrwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, false, false, 0, 100).
+
+hammer_sched_tryrwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, true, false, 0, 100).
+
+hammer_sched_freqread_tryrwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, false, false, 0, 100).
+
+hammer_sched_freqread_tryrwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, true, false, 0, 100).
+
+hammer_sched_long_rwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, false, true, 100, 0).
+
+hammer_sched_long_rwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, true, true, 100, 0).
+
+hammer_sched_long_freqread_rwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, false, true, 100, 0).
+
+hammer_sched_long_freqread_rwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, true, true, 100, 0).
+
+hammer_sched_long_tryrwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, false, false, 100, 100).
+
+hammer_sched_long_tryrwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(false, true, false, 100, 100).
+
+hammer_sched_long_freqread_tryrwlock(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, false, false, 100, 100).
+
+hammer_sched_long_freqread_tryrwlock_check(Config) when is_list(Config) ->
+ hammer_sched_rwlock_test(true, true, false, 100, 100).
+
+hammer_sched_rwlock_test(FreqRead, LockCheck, Blocking, WaitLocked, WaitUnlocked) ->
+ case create_rwlock(FreqRead, LockCheck) of
+ enotsup ->
+ {skipped, "Not supported."};
+ RWLock ->
+ Onln = erlang:system_info(schedulers_online),
+ NWPs = case Onln div 3 of
+ 1 -> case Onln < 4 of
+ true -> 1;
+ false -> 2
+ end;
+ X -> X
+ end,
+ NRPs = Onln - NWPs,
+ NoLockOps = ((((50000000 div Onln)
+ div case {Blocking, WaitLocked} of
+ {false, 0} -> 1;
+ _ -> 10
+ end)
+ div (case WaitLocked == 0 of
+ true -> 1;
+ false -> WaitLocked*250
+ end))
+ div handicap()),
+ ?t:format("NoLockOps=~p~n", [NoLockOps]),
+ Sleep = case Blocking of
+ true -> NoLockOps;
+ false -> NoLockOps div 10
+ end,
+ WPs = lists:map(
+ fun (Sched) ->
+ spawn_opt(
+ fun () ->
+ io:format("Writer on scheduler ~p.~n",
+ [Sched]),
+ Sched = erlang:system_info(scheduler_id),
+ receive go -> gone end,
+ hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ true,
+ WaitLocked,
+ WaitUnlocked,
+ NoLockOps,
+ Sleep),
+ Sched = erlang:system_info(scheduler_id)
+ end,
+ [link, {scheduler, Sched}])
+ end,
+ lists:seq(1, NWPs)),
+ RPs = lists:map(
+ fun (Sched) ->
+ spawn_opt(
+ fun () ->
+ io:format("Reader on scheduler ~p.~n",
+ [Sched]),
+ Sched = erlang:system_info(scheduler_id),
+ receive go -> gone end,
+ hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ false,
+ WaitLocked,
+ WaitUnlocked,
+ NoLockOps,
+ Sleep),
+ Sched = erlang:system_info(scheduler_id)
+ end,
+ [link, {scheduler, Sched}])
+ end,
+ lists:seq(NWPs + 1, NWPs + NRPs)),
+ Procs = WPs ++ RPs,
+ case {Blocking, WaitLocked} of
+ {_, 0} -> ok;
+ {false, _} -> ok;
+ _ -> statistics(runtime)
+ end,
+ lists:foreach(fun (P) -> P ! go end, Procs),
+ lists:foreach(fun (P) ->
+ M = erlang:monitor(process, P),
+ receive
+ {'DOWN', M, process, P, _} ->
+ ok
+ end
+ end,
+ Procs),
+ case {Blocking, WaitLocked} of
+ {_, 0} -> ok;
+ {false, _} -> ok;
+ _ ->
+ {_, RunTime} = statistics(runtime),
+ ?t:format("RunTime=~p~n", [RunTime]),
+ ?line true = RunTime < 500,
+ {comment,
+ "Run-time during test was "
+ ++ integer_to_list(RunTime)
+ ++ " ms."}
+ end
+ end.
+
+hammer_sched_rwlock_proc(_RWLock,
+ _Blocking,
+ _WriteOp,
+ _WaitLocked,
+ _WaitUnlocked,
+ 0,
+ _Sleep) ->
+ ok;
+hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ WriteOp,
+ WaitLocked,
+ WaitUnlocked,
+ Times,
+ Sleep) when Times rem Sleep == 0 ->
+ rwlock_op(RWLock, Blocking, WriteOp, WaitLocked, WaitUnlocked),
+ hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ WriteOp,
+ WaitLocked,
+ WaitUnlocked,
+ Times - 1,
+ Sleep);
+hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ WriteOp,
+ WaitLocked,
+ WaitUnlocked,
+ Times,
+ Sleep) ->
+ rwlock_op(RWLock, Blocking, WriteOp, WaitLocked, 0),
+ hammer_sched_rwlock_proc(RWLock,
+ Blocking,
+ WriteOp,
+ WaitLocked,
+ WaitUnlocked,
+ Times - 1,
+ Sleep).
+
+-define(HAMMER_ETS_RWLOCK_REPEAT_TIMES, 1).
+-define(HAMMER_ETS_RWLOCK_TSIZE, 500).
+
+hammer_ets_rwlock(Config) when is_list(Config) ->
+ {Ops, Procs} = case handicap() of
+ 1 -> {20000, 500};
+ 2 -> {20000, 50};
+ 3 -> {2000, 50};
+ _ -> {200, 50}
+ end,
+ ?t:format("Procs=~p~nOps=~p~n", [Procs, Ops]),
+ lists:foreach(fun (XOpts) ->
+ ?t:format("Running with extra opts: ~p", [XOpts]),
+ hammer_ets_rwlock_test(XOpts, true, 2, Ops,
+ Procs, false)
+ end,
+ [[],
+ [{read_concurrency, true}],
+ [{write_concurrency, true}],
+ [{read_concurrency, true},{write_concurrency, true}]]),
+ ok.
+
+%% Aux funcs
+
+long_rw_test() ->
+ exit(no_nif_implementation).
+
+hammer_rw_test(_Arg) ->
+ exit(no_nif_implementation).
+
+hammer_tryrw_test(_Arg) ->
+ exit(no_nif_implementation).
+
+create_rwlock(_FreqRead, _LockCheck) ->
+ exit(no_nif_implementation).
+
+rwlock_op(_RWLock, _Blocking, _WriteOp, _WaitLocked, _WaitUnlocked) ->
+ exit(no_nif_implementation).
+
+hammer_ets_rwlock_put_data() ->
+ put(?MODULE, {"here are some", data, "to store", make_ref()}).
+
+hammer_ets_rwlock_get_data() ->
+ get(?MODULE).
+
+hammer_ets_rwlock_ops(_T, _UW, _N, _C, _SC, 0) ->
+ ok;
+hammer_ets_rwlock_ops(T, UW, N, C, SC, Tot) when N >= ?HAMMER_ETS_RWLOCK_TSIZE ->
+ hammer_ets_rwlock_ops(T, UW, 0, C, SC, Tot);
+hammer_ets_rwlock_ops(T, UW, N, 0, SC, Tot) ->
+ case UW of
+ true ->
+ true = ets:insert(T, {N, Tot, hammer_ets_rwlock_get_data()});
+ false ->
+ [{N, _, _}] = ets:lookup(T, N)
+ end,
+ hammer_ets_rwlock_ops(T, UW, N+1, SC, SC, Tot-1);
+hammer_ets_rwlock_ops(T, UW, N, C, SC, Tot) ->
+ case UW of
+ false ->
+ true = ets:insert(T, {N, Tot, hammer_ets_rwlock_get_data()});
+ true ->
+ [{N, _, _}] = ets:lookup(T, N)
+ end,
+ hammer_ets_rwlock_ops(T, UW, N+1, C-1, SC, Tot-1).
+
+hammer_ets_rwlock_init(T, N) when N < ?HAMMER_ETS_RWLOCK_TSIZE ->
+ ets:insert(T, {N, N, N}),
+ hammer_ets_rwlock_init(T, N+1);
+hammer_ets_rwlock_init(_T, _N) ->
+ ok.
+
+hammer_ets_rwlock_test(XOpts, UW, C, N, NP, SC) ->
+ receive after 100 -> ok end,
+ {TP, TM} = spawn_monitor(
+ fun () ->
+ _L = repeat_list(
+ fun () ->
+ Caller = self(),
+ T = fun () ->
+ Parent = self(),
+ hammer_ets_rwlock_put_data(),
+ T=ets:new(x, [public | XOpts]),
+ hammer_ets_rwlock_init(T, 0),
+ Ps0 = repeat_list(
+ fun () ->
+ spawn_link(
+ fun () ->
+ hammer_ets_rwlock_put_data(),
+ receive go -> ok end,
+ hammer_ets_rwlock_ops(T, UW, N, C, C, N),
+ Parent ! {done, self()},
+ receive after infinity -> ok end
+ end)
+ end,
+ NP - case SC of
+ false -> 0;
+ _ -> 1
+ end),
+ Ps = case SC of
+ false -> Ps0;
+ _ -> [spawn_link(fun () ->
+ hammer_ets_rwlock_put_data(),
+ receive go -> ok end,
+ hammer_ets_rwlock_ops(T, UW, N, SC, SC, N),
+ Parent ! {done, self()},
+ receive after infinity -> ok end
+ end) | Ps0]
+ end,
+ Start = now(),
+ lists:foreach(fun (P) -> P ! go end, Ps),
+ lists:foreach(fun (P) -> receive {done, P} -> ok end end, Ps),
+ Stop = now(),
+ lists:foreach(fun (P) ->
+ unlink(P),
+ exit(P, bang),
+ M = erlang:monitor(process, P),
+ receive
+ {'DOWN', M, process, P, _} -> ok
+ end
+ end, Ps),
+ Res = timer:now_diff(Stop, Start)/1000000,
+ Caller ! {?MODULE, self(), Res}
+ end,
+ TP = spawn_link(T),
+ receive
+ {?MODULE, TP, Res} ->
+ Res
+ end
+ end,
+ ?HAMMER_ETS_RWLOCK_REPEAT_TIMES)
+ end),
+ receive
+ {'DOWN', TM, process, TP, _} -> ok
+ end.
+
+repeat_list(Fun, N) ->
+ repeat_list(Fun, N, []).
+
+repeat_list(_Fun, 0, Acc) ->
+ Acc;
+repeat_list(Fun, N, Acc) ->
+ repeat_list(Fun, N-1, [Fun()|Acc]).
+
+
+handicap() ->
+ X0 = case catch (erlang:system_info(logical_processors_available) >=
+ erlang:system_info(schedulers_online)) of
+ true -> 1;
+ _ -> 2
+ end,
+ case erlang:system_info(build_type) of
+ opt ->
+ X0;
+ ReallySlow when ReallySlow == debug;
+ ReallySlow == valgrind;
+ ReallySlow == purify ->
+ X0*3;
+ _Slow ->
+ X0*2
+ end.
+
diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..b6c843269c
--- /dev/null
+++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src
@@ -0,0 +1,30 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 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%
+#
+
+include @erts_lib_include_internal_generated@@[email protected]
+include @erts_lib_include_internal_generated@@DS@erts_internal.mk
+
+NIF_LIBS = mtx_SUITE@dll@
+
+SHLIB_EXTRA_CFLAGS = $(ETHR_DEFS) -I@erts_lib_include_internal@ -I@erts_lib_include_internal_generated@
+LIBS = @ERTS_LIBS@
+
+all: $(NIF_LIBS)
+
+@SHLIB_RULES@
diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
new file mode 100644
index 0000000000..818023211c
--- /dev/null
+++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
@@ -0,0 +1,692 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 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%
+ */
+
+/*
+ * Stress tests of rwmutex implementation.
+ *
+ * Author: Rickard Green
+ */
+
+#include "erl_nif.h"
+
+#ifdef __WIN32__
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#else
+# include "ethread.h"
+# include "erl_misc_utils.h"
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+static int
+fail(const char *file, int line, const char *function, const char *assertion);
+
+#undef ASSERT
+#define ASSERT(X) ((void) ((X) ? 1 : fail(__FILE__, __LINE__, __func__, #X)))
+
+#ifdef __WIN32__
+/*
+ * We cannot access the ethread symbols directly; test
+ * what we got in the nif api instead...
+ */
+#define HAVE_FREQREAD_SUPPORT 0
+#define RWMUTEX_T ErlNifRWLock
+#define RWMUTEX_CREATE(FR) enif_rwlock_create("dummy")
+#define RWMUTEX_DESTROY enif_rwlock_destroy
+#define RWMUTEX_WLOCK enif_rwlock_rwlock
+#define RWMUTEX_TRYWLOCK enif_rwlock_tryrwlock
+#define RWMUTEX_WUNLOCK enif_rwlock_rwunlock
+#define RWMUTEX_TRYRLOCK enif_rwlock_tryrlock
+#define RWMUTEX_RLOCK enif_rwlock_rlock
+#define RWMUTEX_RUNLOCK enif_rwlock_runlock
+#define THR_ID ErlNifTid
+#define THR_CREATE(A, B, C, D) enif_thread_create("dummy", (A), (B), (C), (D))
+#define THR_JOIN enif_thread_join
+#define ATOMIC_T volatile LONG
+#define ATOMIC_INIT(VarP, Val) (*(VarP) = (Val))
+#define ATOMIC_SET(VarP, Val) (*(VarP) = (Val))
+#define ATOMIC_READ(VarP) (*(VarP))
+#define ATOMIC_INC InterlockedIncrement
+#define ATOMIC_DEC InterlockedDecrement
+
+#else
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+# define HAVE_FREQREAD_SUPPORT 1
+#else
+# define HAVE_FREQREAD_SUPPORT 0
+#endif
+
+#define RWMUTEX_T ethr_rwmutex
+static ethr_rwmutex *
+RWMUTEX_CREATE(int freqread)
+{
+ ethr_rwmutex *rwmtx = enif_alloc(sizeof(ethr_rwmutex));
+ ethr_rwmutex_opt rwmtx_opt = ETHR_RWMUTEX_OPT_DEFAULT_INITER;
+ if (freqread)
+ rwmtx_opt.type = ETHR_RWMUTEX_TYPE_FREQUENT_READ;
+ ASSERT(rwmtx);
+ ASSERT(ethr_rwmutex_init_opt(rwmtx, &rwmtx_opt) == 0);
+ return rwmtx;
+}
+static void
+RWMUTEX_DESTROY(ethr_rwmutex *rwmtx)
+{
+ ASSERT(ethr_rwmutex_destroy(rwmtx) == 0);
+ enif_free(rwmtx);
+}
+#define RWMUTEX_TRYWLOCK ethr_rwmutex_tryrwlock
+#define RWMUTEX_WLOCK ethr_rwmutex_rwlock
+#define RWMUTEX_WUNLOCK ethr_rwmutex_rwunlock
+#define RWMUTEX_TRYRLOCK ethr_rwmutex_tryrlock
+#define RWMUTEX_RLOCK ethr_rwmutex_rlock
+#define RWMUTEX_RUNLOCK ethr_rwmutex_runlock
+#define THR_ID ethr_tid
+#define THR_CREATE ethr_thr_create
+#define THR_JOIN ethr_thr_join
+#define ATOMIC_T ethr_atomic_t
+#define ATOMIC_INIT ethr_atomic_init
+#define ATOMIC_SET ethr_atomic_set
+#define ATOMIC_READ ethr_atomic_read
+#define ATOMIC_INC ethr_atomic_inc
+#define ATOMIC_DEC ethr_atomic_dec
+
+#endif
+
+
+#if !defined(__func__)
+# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
+# if !defined(__GNUC__) || __GNUC__ < 2
+# define __func__ "[unknown_function]"
+# else
+# define __func__ __FUNCTION__
+# endif
+# endif
+#endif
+
+static void milli_sleep(int ms);
+static int get_bool(ErlNifEnv* env, ERL_NIF_TERM term);
+
+/*
+ * Long rwlock testcase
+ */
+
+#define LONG_RW_NO_W_THREADS 6
+#define LONG_RW_NO_THREADS 20
+#define LONG_RW_NO_WLOCK_COUNT 100
+
+typedef struct {
+ RWMUTEX_T *rwlock;
+ ATOMIC_T *is_wlocked;
+ ATOMIC_T *is_rlocked;
+ int *stop;
+ int *count;
+ int sleep;
+} long_rw_t;
+
+static void *
+long_rw_w(void *varg)
+{
+ long_rw_t *arg = varg;
+ int stop = 0;
+ do {
+ RWMUTEX_WLOCK(arg->rwlock);
+ ASSERT(!ATOMIC_READ(arg->is_wlocked));
+ ATOMIC_SET(arg->is_wlocked, 1);
+ ASSERT(!ATOMIC_READ(arg->is_rlocked));
+ milli_sleep(arg->sleep);
+ if (++(*arg->count) > LONG_RW_NO_WLOCK_COUNT)
+ stop = *arg->stop = 1;
+ ATOMIC_SET(arg->is_wlocked, 0);
+ ASSERT(!ATOMIC_READ(arg->is_rlocked));
+ RWMUTEX_WUNLOCK(arg->rwlock);
+ } while (!stop);
+ return NULL;
+}
+
+static void *
+long_rw_r(void *varg)
+{
+ long_rw_t *arg = varg;
+ int stop;
+ do {
+ RWMUTEX_RLOCK(arg->rwlock);
+ ASSERT(!ATOMIC_READ(arg->is_wlocked));
+ ATOMIC_INC(arg->is_rlocked);
+ milli_sleep(arg->sleep);
+ stop = *arg->stop;
+ ATOMIC_DEC(arg->is_rlocked);
+ ASSERT(!ATOMIC_READ(arg->is_wlocked));
+ RWMUTEX_RUNLOCK(arg->rwlock);
+ } while (!stop);
+ return NULL;
+}
+
+
+static ERL_NIF_TERM long_rw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ int res, freqread, i, count, stop;
+ ATOMIC_T is_wlocked, is_rlocked;
+ THR_ID tid[LONG_RW_NO_THREADS];
+ long_rw_t arg;
+ long_rw_t targ[LONG_RW_NO_THREADS];
+
+ ATOMIC_INIT(&is_wlocked, 0);
+ ATOMIC_INIT(&is_rlocked, 0);
+
+ freqread = 0;
+
+ arg.is_wlocked = &is_wlocked;
+ arg.is_rlocked = &is_rlocked;
+ arg.count = &count;
+ arg.stop = &stop;
+
+ restart:
+
+ stop = 0;
+ count = 0;
+
+ arg.rwlock = RWMUTEX_CREATE(freqread);
+
+ ASSERT(arg.rwlock);
+
+ for (i = 0; i < LONG_RW_NO_W_THREADS; i++) {
+ targ[i] = arg;
+ targ[i].sleep = 100 + i*10;
+ ASSERT(THR_CREATE(&tid[i], long_rw_w, &targ[i], NULL) == 0);
+ }
+ for (; i < LONG_RW_NO_THREADS; i++) {
+ targ[i] = arg;
+ targ[i].sleep = 100;
+ ASSERT(THR_CREATE(&tid[i], long_rw_r, &targ[i], NULL) == 0);
+ }
+ for (i = 0; i < LONG_RW_NO_THREADS; i++)
+ ASSERT(THR_JOIN(tid[i], NULL) == 0);
+
+ ASSERT(!ATOMIC_READ(arg.is_wlocked));
+ ASSERT(!ATOMIC_READ(arg.is_rlocked));
+
+ RWMUTEX_DESTROY(arg.rwlock);
+
+ if (HAVE_FREQREAD_SUPPORT && !freqread) {
+ freqread = 1;
+ goto restart;
+ }
+
+ if (freqread)
+ return enif_make_atom(env, "ok");
+ else
+ return enif_make_tuple2(env,
+ enif_make_atom(env,
+ "comment"),
+ enif_make_string(env,
+ "No frequent read test made.",
+ ERL_NIF_LATIN1));
+}
+
+/*
+ * Hammer rwlock testcase
+ */
+
+#define HAMMER_RW_NO_W_THREADS 6
+#define HAMMER_RW_NO_THREADS 20
+#define HAMMER_RW_NO_WLOCK_COUNT 1000000
+
+typedef struct {
+ RWMUTEX_T *rwlock;
+ ATOMIC_T is_locked;
+ int lock_check;
+ int stop;
+ int count;
+} hammer_rw_t;
+
+static void *
+hammer_rw_w(void *varg)
+{
+ hammer_rw_t *arg = varg;
+ int stop = 0;
+ do {
+ RWMUTEX_WLOCK(arg->rwlock);
+ if (arg->lock_check) {
+ ASSERT(!ATOMIC_READ(&arg->is_locked));
+ ATOMIC_SET(&arg->is_locked, -1);
+ }
+ if (++arg->count > HAMMER_RW_NO_WLOCK_COUNT)
+ stop = arg->stop = 1;
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) == -1);
+ ATOMIC_SET(&arg->is_locked, 0);
+ }
+ RWMUTEX_WUNLOCK(arg->rwlock);
+ } while (!stop);
+ return NULL;
+}
+
+static void *
+hammer_rw_r(void *varg)
+{
+ hammer_rw_t *arg = varg;
+ int stop;
+ do {
+ RWMUTEX_RLOCK(arg->rwlock);
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) >= 0);
+ ATOMIC_INC(&arg->is_locked);
+ }
+ stop = arg->stop;
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) > 0);
+ ATOMIC_DEC(&arg->is_locked);
+ }
+ RWMUTEX_RUNLOCK(arg->rwlock);
+ } while (!stop);
+ return NULL;
+}
+
+
+static ERL_NIF_TERM hammer_rw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ hammer_rw_t arg;
+ char buf[10];
+ int res, freqread, i;
+ THR_ID tid[HAMMER_RW_NO_THREADS];
+
+ if (argc != 1)
+ goto badarg;
+
+ arg.lock_check = get_bool(env, argv[0]);
+ if (arg.lock_check < 0)
+ goto badarg;
+
+ ATOMIC_INIT(&arg.is_locked, 0);
+
+ freqread = 0;
+
+ restart:
+ arg.stop = 0;
+ arg.count = 0;
+
+ arg.rwlock = RWMUTEX_CREATE(freqread);
+
+ ASSERT(arg.rwlock);
+
+ for (i = 0; i < HAMMER_RW_NO_W_THREADS; i++)
+ ASSERT(THR_CREATE(&tid[i], hammer_rw_w, &arg, NULL) == 0);
+ for (; i < HAMMER_RW_NO_THREADS; i++)
+ ASSERT(THR_CREATE(&tid[i], hammer_rw_r, &arg, NULL) == 0);
+ for (i = 0; i < HAMMER_RW_NO_THREADS; i++)
+ ASSERT(THR_JOIN(tid[i], NULL) == 0);
+
+ ASSERT(!ATOMIC_READ(&arg.is_locked));
+
+ RWMUTEX_DESTROY(arg.rwlock);
+
+ if (HAVE_FREQREAD_SUPPORT && !freqread) {
+ freqread = 1;
+ goto restart;
+ }
+
+ if (freqread)
+ return enif_make_atom(env, "ok");
+ else
+ return enif_make_tuple2(env,
+ enif_make_atom(env,
+ "comment"),
+ enif_make_string(env,
+ "No frequent read test made.",
+ ERL_NIF_LATIN1));
+ badarg:
+ return enif_make_badarg(env);
+}
+
+/*
+ * Hammer try rwlock testcase
+ */
+
+#define HAMMER_TRYRW_NO_W_THREADS 10
+#define HAMMER_TRYRW_NO_THREADS 20
+#define HAMMER_TRYRW_NO_WLOCK_COUNT 10000000
+#define HAMMER_TRYRW_NO_RLOCK_COUNT 10000000
+#define HAMMER_TRYRW_NO_WLOCK_WAIT_COUNT ((10*HAMMER_TRYRW_NO_WLOCK_COUNT)/8)
+#define HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT ((10*HAMMER_TRYRW_NO_RLOCK_COUNT)/8)
+
+typedef struct {
+ RWMUTEX_T *rwlock;
+ ATOMIC_T is_locked;
+ int lock_check;
+ int w_count;
+ ATOMIC_T r_count;
+} hammer_tryrw_t;
+
+static void *
+hammer_tryrw_w(void *varg)
+{
+ hammer_tryrw_t *arg = varg;
+ int stop = 0;
+ int wait = 0;
+ do {
+ while (EBUSY == RWMUTEX_TRYWLOCK(arg->rwlock));
+ if (arg->lock_check) {
+ ASSERT(!ATOMIC_READ(&arg->is_locked));
+ ATOMIC_SET(&arg->is_locked, -1);
+ }
+ if (++arg->w_count > HAMMER_TRYRW_NO_WLOCK_COUNT)
+ stop = 1;
+ else if (arg->w_count > HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT)
+ wait = 1;
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) == -1);
+ ATOMIC_SET(&arg->is_locked, 0);
+ }
+ RWMUTEX_WUNLOCK(arg->rwlock);
+ if (wait)
+ milli_sleep(1);
+ } while (!stop);
+ return NULL;
+}
+
+static void *
+hammer_tryrw_r(void *varg)
+{
+ hammer_tryrw_t *arg = varg;
+ long r_count;
+ int stop = 0;
+ int wait = 0;
+ do {
+ while (EBUSY == RWMUTEX_TRYRLOCK(arg->rwlock));
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) >= 0);
+ ATOMIC_INC(&arg->is_locked);
+ }
+ ATOMIC_INC(&arg->r_count);
+ r_count = ATOMIC_READ(&arg->r_count);
+ if (r_count > HAMMER_TRYRW_NO_RLOCK_COUNT)
+ stop = 1;
+ else if (r_count > HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT)
+ wait = 1;
+ if (arg->lock_check) {
+ ASSERT(ATOMIC_READ(&arg->is_locked) > 0);
+ ATOMIC_DEC(&arg->is_locked);
+ }
+ RWMUTEX_RUNLOCK(arg->rwlock);
+ if (wait)
+ milli_sleep(1);
+ } while (!stop);
+ return NULL;
+}
+
+
+static ERL_NIF_TERM hammer_tryrw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ hammer_tryrw_t arg;
+ char buf[10];
+ int res, freqread, i;
+ THR_ID tid[HAMMER_TRYRW_NO_THREADS];
+
+ if (argc != 1)
+ goto badarg;
+
+ arg.lock_check = get_bool(env, argv[0]);
+ if (arg.lock_check < 0)
+ goto badarg;
+
+ ATOMIC_INIT(&arg.is_locked, 0);
+ freqread = 0;
+
+ restart:
+
+ arg.w_count = 0;
+ ATOMIC_INIT(&arg.r_count, 0);
+
+ arg.rwlock = RWMUTEX_CREATE(freqread);
+
+ ASSERT(arg.rwlock);
+
+ for (i = 0; i < HAMMER_TRYRW_NO_W_THREADS; i++)
+ ASSERT(THR_CREATE(&tid[i], hammer_tryrw_w, &arg, NULL) == 0);
+ for (; i < HAMMER_TRYRW_NO_THREADS; i++)
+ ASSERT(THR_CREATE(&tid[i], hammer_tryrw_r, &arg, NULL) == 0);
+ for (i = 0; i < HAMMER_TRYRW_NO_THREADS; i++)
+ ASSERT(THR_JOIN(tid[i], NULL) == 0);
+
+ ASSERT(!ATOMIC_READ(&arg.is_locked));
+
+ RWMUTEX_DESTROY(arg.rwlock);
+
+ if (HAVE_FREQREAD_SUPPORT && !freqread) {
+ freqread = 1;
+ goto restart;
+ }
+
+ if (freqread)
+ return enif_make_atom(env, "ok");
+ else
+ return enif_make_tuple2(env,
+ enif_make_atom(env,
+ "comment"),
+ enif_make_string(env,
+ "No frequent read test made.",
+ ERL_NIF_LATIN1));
+ badarg:
+ return enif_make_badarg(env);
+}
+
+typedef struct {
+ int lock_check;
+ ATOMIC_T is_locked;
+ RWMUTEX_T *rwlock;
+} rwlock_resource_t;
+
+static void
+rwlock_destructor(ErlNifEnv* env, void* obj)
+{
+ rwlock_resource_t *rwlr = obj;
+ if (rwlr->lock_check)
+ ASSERT(!ATOMIC_READ(&rwlr->is_locked));
+ RWMUTEX_DESTROY(rwlr->rwlock);
+}
+
+/*
+ * create_rwlock(FreqRead, LockCheck)
+ */
+
+static ERL_NIF_TERM
+create_rwlock(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ int lock_check, freqread;
+ ERL_NIF_TERM rwlock_term;
+ rwlock_resource_t *rwlr;
+ char buf[100];
+
+ if (argc != 2)
+ goto badarg;
+
+ freqread = get_bool(env, argv[0]);
+ if (freqread < 0)
+ goto badarg;
+
+ if (!HAVE_FREQREAD_SUPPORT && freqread)
+ return enif_make_atom(env, "enotsup");
+
+ lock_check = get_bool(env, argv[1]);
+ if (lock_check < 0)
+ goto badarg;
+
+ rwlr = enif_alloc_resource(enif_priv_data(env), sizeof(rwlock_resource_t));
+ rwlr->lock_check = lock_check;
+ ATOMIC_INIT(&rwlr->is_locked, 0);
+ rwlr->rwlock = RWMUTEX_CREATE(freqread);
+ rwlock_term = enif_make_resource(env, rwlr);
+ enif_release_resource(rwlr);
+ return rwlock_term;
+
+ badarg:
+ return enif_make_badarg(env);
+}
+
+/*
+ * rwlock_op(RWLock, Blocking, WriteOp, WaitTime)
+ */
+
+static ERL_NIF_TERM
+rwlock_op(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ rwlock_resource_t *rwlr;
+ int blocking, write, wait_locked, wait_unlocked;
+
+ if (argc != 5)
+ goto badarg;
+
+ if (!enif_get_resource(env, argv[0], enif_priv_data(env), (void **) &rwlr))
+ goto badarg;
+
+ blocking = get_bool(env, argv[1]);
+ if (blocking < 0)
+ goto badarg;
+
+ write = get_bool(env, argv[2]);
+ if (write < 0)
+ goto badarg;
+
+ if (!enif_get_int(env, argv[3], &wait_locked))
+ goto badarg;
+ if (wait_locked < 0)
+ goto badarg;
+
+ if (!enif_get_int(env, argv[4], &wait_unlocked))
+ goto badarg;
+ if (wait_unlocked < 0)
+ goto badarg;
+
+ if (write) {
+ if (blocking)
+ RWMUTEX_WLOCK(rwlr->rwlock);
+ else
+ while (EBUSY == RWMUTEX_TRYWLOCK(rwlr->rwlock));
+ if (rwlr->lock_check) {
+ ASSERT(!ATOMIC_READ(&rwlr->is_locked));
+ ATOMIC_SET(&rwlr->is_locked, -1);
+ }
+ }
+ else {
+ if (blocking)
+ RWMUTEX_RLOCK(rwlr->rwlock);
+ else
+ while (EBUSY == RWMUTEX_TRYRLOCK(rwlr->rwlock));
+ if (rwlr->lock_check) {
+ ASSERT(ATOMIC_READ(&rwlr->is_locked) >= 0);
+ ATOMIC_INC(&rwlr->is_locked);
+ }
+ }
+
+ if (wait_locked)
+ milli_sleep(wait_locked);
+
+ if (write) {
+ if (rwlr->lock_check) {
+ ASSERT(ATOMIC_READ(&rwlr->is_locked) == -1);
+ ATOMIC_SET(&rwlr->is_locked, 0);
+ }
+ RWMUTEX_WUNLOCK(rwlr->rwlock);
+ }
+ else {
+ if (rwlr->lock_check) {
+ ASSERT(ATOMIC_READ(&rwlr->is_locked) > 0);
+ ATOMIC_DEC(&rwlr->is_locked);
+ }
+ RWMUTEX_RUNLOCK(rwlr->rwlock);
+ }
+
+ if (wait_unlocked)
+ milli_sleep(wait_unlocked);
+
+ return enif_make_atom(env, "ok");
+ badarg:
+ return enif_make_badarg(env);
+}
+
+static int load_nif_lib(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ *priv_data = enif_open_resource_type(env,
+ NULL,
+ "rwlock_resource",
+ rwlock_destructor,
+ ERL_NIF_RT_CREATE,
+ NULL);
+ if (*priv_data)
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * 0 -> false
+ * >0 -> true
+ * <0 -> error
+ */
+
+static int
+get_bool(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+ int res;
+ char buf[10];
+
+ res = enif_get_atom(env, term, buf, sizeof(buf), ERL_NIF_LATIN1);
+ if (res == 0)
+ return -1;
+ if (strcmp("false", buf) == 0)
+ return 0;
+ else if (strcmp("true", buf) == 0)
+ return 1;
+ else
+ return -1;
+}
+
+static int
+fail(const char *file, int line, const char *function, const char *assertion)
+{
+ fprintf(stderr, "%s:%d: Assertion failed in %s(): %s\n",
+ file, line, function, assertion);
+ abort();
+}
+
+static void
+milli_sleep(int ms)
+{
+#ifdef __WIN32__
+ Sleep(ms);
+#else
+ while (erts_milli_sleep(ms) != 0);
+#endif
+}
+
+static ErlNifFunc nif_funcs[] = {
+ {"long_rw_test", 0, long_rw_test},
+ {"hammer_rw_test", 1, hammer_rw_test},
+ {"hammer_tryrw_test", 1, hammer_tryrw_test},
+ {"create_rwlock", 2, create_rwlock},
+ {"rwlock_op", 5, rwlock_op}
+};
+
+ERL_NIF_INIT(mtx_SUITE, nif_funcs, load_nif_lib, NULL, NULL, NULL)
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 6d89653623..7fe532abd0 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -2302,7 +2302,8 @@ load_driver(Dir, Driver) ->
end.
-close_deaf_port(doc) -> ["Send data to port program that does not read it, then close port."];
+close_deaf_port(doc) -> ["Send data to port program that does not read it, then close port."
+ "Primary targeting Windows to test threaded_handle_closer in sys.c"];
close_deaf_port(suite) -> [];
close_deaf_port(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:seconds(100)),
@@ -2312,24 +2313,24 @@ close_deaf_port(Config) when is_list(Config) ->
?line erlang:port_command(Port,"Hello, can you hear me!?!?"),
?line port_close(Port),
- close_deaf_port_1(0, DeadPort).
+ Res = close_deaf_port_1(0, DeadPort),
+ io:format("Waiting for OS procs to terminate...\n"),
+ receive after 5*1000 -> ok end,
+ ?line test_server:timetrap_cancel(Dog),
+ Res.
close_deaf_port_1(1000, _) ->
ok;
close_deaf_port_1(N, Cmd) ->
- Timeout = integer_to_list(random:uniform(10*1000)),
- try open_port({spawn,Cmd++" "++Timeout},[]) of
+ Timeout = integer_to_list(random:uniform(5*1000)),
+ ?line try open_port({spawn_executable,Cmd},[{args,[Timeout]}]) of
Port ->
?line erlang:port_command(Port,"Hello, can you hear me!?!?"),
?line port_close(Port),
close_deaf_port_1(N+1, Cmd)
catch
- exit:eagain ->
+ _:eagain ->
{comment, "Could not spawn more than " ++ integer_to_list(N) ++ " OS processes."}
end.
-repeat(0, _) -> ok;
-repeat(Cnt, Fun) ->
- Fun(),
- repeat(Cnt-1, Fun).
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index e866511153..4754328c0b 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -178,7 +178,7 @@ MC_OUTPUTS= \
MT_FLAG="-MD"
endif
INET_GETHOST = $(BINDIR)/inet_gethost.exe
-INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer.exe $(BINDIR)/dialyzer.exe $(BINDIR)/erlc.exe $(BINDIR)/start_erl.exe $(BINDIR)/escript.exe $(BINDIR)/run_test.exe
+INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer.exe $(BINDIR)/dialyzer.exe $(BINDIR)/erlc.exe $(BINDIR)/start_erl.exe $(BINDIR)/escript.exe $(BINDIR)/ct_run.exe
INSTALL_SRC = $(WINETC)/start_erl.c $(WINETC)/Nmakefile.start_erl
ERLEXECDIR=.
INSTALL_LIBS =
@@ -211,7 +211,7 @@ ERLSRV_OBJECTS=
MC_OUTPUTS=
INET_GETHOST = $(BINDIR)/inet_gethost@EXEEXT@
INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer@EXEEXT@ $(BINDIR)/dialyzer@EXEEXT@ \
- $(BINDIR)/erlc@EXEEXT@ $(BINDIR)/escript@EXEEXT@ $(BINDIR)/run_test@EXEEXT@ \
+ $(BINDIR)/erlc@EXEEXT@ $(BINDIR)/escript@EXEEXT@ $(BINDIR)/ct_run@EXEEXT@ \
$(BINDIR)/run_erl $(BINDIR)/to_erl $(BINDIR)/dyn_erl
INSTALL_EMBEDDED_DATA = ../unix/start.src ../unix/start_erl.src
INSTALL_TOP = Install
@@ -274,7 +274,7 @@ endif
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/dyn_erl.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/safe_string.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/typer.o
- rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/run_test.o
+ rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/ct_run.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/werl.o
@@ -350,11 +350,11 @@ $(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o
$(OBJDIR)/escript.o: escript.c
$(CC) $(CFLAGS) -o $@ -c escript.c
-$(BINDIR)/run_test@EXEEXT@: $(OBJDIR)/run_test.o
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/run_test.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-$(OBJDIR)/run_test.o: run_test.c
- $(CC) $(CFLAGS) -o $@ -c run_test.c
+$(OBJDIR)/ct_run.o: ct_run.c
+ $(CC) $(CFLAGS) -o $@ -c ct_run.c
#------------------------------------------------------------------------
diff --git a/erts/etc/common/run_test.c b/erts/etc/common/ct_run.c
index 042b8571ca..7aaab716f7 100644
--- a/erts/etc/common/run_test.c
+++ b/erts/etc/common/ct_run.c
@@ -85,6 +85,7 @@ static char* strsave(char* string);
static void push_words(char* src);
static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
+static void print_deprecation_warning(char *progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
#endif
@@ -131,6 +132,8 @@ main(int argc, char** argv)
int erl_args;
char** argv0 = argv;
+ print_deprecation_warning(argv[0]);
+
emulator = get_default_emulator(argv[0]);
/*
@@ -391,7 +394,7 @@ run_erlang(char* progname, char** argv)
status = my_spawnvp(argv)/*_spawnvp(_P_WAIT,progname,argv)*/;
if (status == -1) {
- fprintf(stderr, "run_test: Error executing '%s': %d", progname,
+ fprintf(stderr, "ct_run: Error executing '%s': %d", progname,
GetLastError());
}
return status;
@@ -411,7 +414,7 @@ error(char* format, ...)
va_start(ap, format);
erts_vsnprintf(sbuf, sizeof(sbuf), format, ap);
va_end(ap);
- fprintf(stderr, "run_test: %s\n", sbuf);
+ fprintf(stderr, "ct_run: %s\n", sbuf);
exit(1);
}
@@ -432,6 +435,27 @@ strsave(char* string)
return p;
}
+/* Instead of making sure basename exists, we do our own */
+static char *simple_basename(char *path)
+{
+ char *ptr;
+ for (ptr = path; *ptr != '\0'; ++ptr) {
+ if (*ptr == '/' || *ptr == '\\') {
+ path = ptr + 1;
+ }
+ }
+ return path;
+}
+
+static void print_deprecation_warning(char* progpath)
+{
+ char *basename = simple_basename(progpath);
+ if(strcmp(basename,"run_test") == 0 ||
+ strcmp(basename, "run_test.exe") == 0) {
+ printf("---***---\nDeprecated: run_test is deprecated and will be removed in R16B,\n please use ct_run instead\n---***---\n");
+ }
+}
+
static char*
get_default_emulator(char* progname)
{
diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src
index 7dead62ab0..8f40c43874 100644
--- a/erts/etc/unix/Install.src
+++ b/erts/etc/unix/Install.src
@@ -89,9 +89,12 @@ cp -p $ERL_ROOT/erts-%I_VSN%/bin/erl .
cp -p $ERL_ROOT/erts-%I_VSN%/bin/erlc .
cp -p $ERL_ROOT/erts-%I_VSN%/bin/dialyzer .
cp -p $ERL_ROOT/erts-%I_VSN%/bin/typer .
-cp -p $ERL_ROOT/erts-%I_VSN%/bin/run_test .
+cp -p $ERL_ROOT/erts-%I_VSN%/bin/ct_run .
cp -p $ERL_ROOT/erts-%I_VSN%/bin/escript .
+# Remove in R16B
+ln -s ct_run run_test
+
#
# Set a soft link to epmd
# This should not be done for an embedded system!
diff --git a/erts/etc/unix/format_man_pages b/erts/etc/unix/format_man_pages
index 2c4f6eee4f..93dcdcd8fa 100644
--- a/erts/etc/unix/format_man_pages
+++ b/erts/etc/unix/format_man_pages
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-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
@@ -59,34 +59,21 @@ esac
# Create the 'cat' directories (probably not needed)
#
-cd $ERL_ROOT
+cd $ERL_ROOT/man
-if [ ! -d man/cat1 ]
-then
- mkdir man/cat1
-fi
+for d in 0 1 2 3 4 5 6 7 8 9
+do
+ if [ ! -d cat$d ]
+ then
+ mkdir cat$d
+ fi
-if [ ! -d man/cat3 ]
-then
- mkdir man/cat3
-fi
-
-if [ ! -d man/cat4 ]
-then
- mkdir man/cat4
-fi
-
-if [ ! -d man/cat6 ]
-then
- mkdir man/cat6
-fi
+done
#
# Cleanup old formatting
#
-cd $ERL_ROOT/man
-
rm -f whatis windex
# Remove old cat files
diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c
index ca814e3f80..6e60512f6d 100644
--- a/erts/etc/win32/Install.c
+++ b/erts/etc/win32/Install.c
@@ -46,7 +46,7 @@ int main(int argc, char **argv)
HANDLE module = GetModuleHandle(NULL);
char *binaries[] = { "erl.exe", "werl.exe", "erlc.exe",
"dialyzer.exe", "typer.exe",
- "escript.exe", "run_test.exe", NULL };
+ "escript.exe", "ct_run.exe", NULL };
char *scripts[] = { "start_clean.boot", "start_sasl.boot", NULL };
char fromname[MAX_PATH];
char toname[MAX_PATH];
@@ -172,6 +172,20 @@ int main(int argc, char **argv)
}
}
+ // Remove in R16B
+ sprintf(fromname,"%s\\%s",bin_dir,"ct_run.exe");
+ sprintf(toname,"%s\\%s",bin_dir,"run_test.exe");
+ if (GetFileAttributes(fromname) == 0xFFFFFFFF) {
+ fprintf(stderr,"Could not find file %s\n",
+ fromname);
+ exit(1);
+ }
+ if (!CopyFile(fromname,toname,FALSE)) {
+ fprintf(stderr,"Could not copy file %s to %s\n",
+ fromname,toname);
+ fprintf(stderr,"Continuing installation anyway...\n");
+ }
+
for (i = 0; scripts[i] != NULL; ++i) {
sprintf(fromname,"%s\\%s",release_dir,scripts[i]);
sprintf(toname,"%s\\%s",bin_dir,scripts[i]);
diff --git a/erts/etc/win32/cygwin_tools/vc/ld.sh b/erts/etc/win32/cygwin_tools/vc/ld.sh
index 9a38c10748..406c63ffee 100755
--- a/erts/etc/win32/cygwin_tools/vc/ld.sh
+++ b/erts/etc/win32/cygwin_tools/vc/ld.sh
@@ -158,7 +158,7 @@ else
fi
p=$$
-CMD="$linktype -nologo -incremental:no $CMD $STDLIB $DEFAULT_LIBRARIES"
+CMD="$linktype -nologo -incremental:no -largeaddressaware $CMD $STDLIB $DEFAULT_LIBRARIES"
if [ "X$LD_SH_DEBUG_LOG" != "X" ]; then
echo ld.sh "$SAVE" >>$LD_SH_DEBUG_LOG
echo link.exe $CMD >>$LD_SH_DEBUG_LOG
diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h
index 8d9d5e3d08..636fdc1e2f 100644
--- a/erts/include/internal/ethr_mutex.h
+++ b/erts/include/internal/ethr_mutex.h
@@ -33,6 +33,13 @@
# define ETHR_MTX_HARD_DEBUG
#endif
+#if 0
+# define ETHR_MTX_CHK_EXCL
+#if 1
+# define ETHR_MTX_CHK_NON_EXCL
+#endif
+#endif
+
#ifdef ETHR_MTX_HARD_DEBUG
# ifdef __GNUC__
# warning ETHR_MTX_HARD_DEBUG
@@ -49,6 +56,15 @@
#if defined(ETHR_USE_OWN_RWMTX_IMPL__) || defined(ETHR_USE_OWN_MTX_IMPL__)
+#ifdef ETHR_DEBUG
+# ifndef ETHR_MTX_CHK_EXCL
+# define ETHR_MTX_CHK_EXCL
+# endif
+# ifndef ETHR_MTX_CHK_NON_EXCL
+# define ETHR_MTX_CHK_NON_EXCL
+# endif
+#endif
+
#if 0
# define ETHR_MTX_Q_LOCK_SPINLOCK__
# define ETHR_MTX_QLOCK_TYPE__ ethr_spinlock_t
@@ -68,8 +84,8 @@
/* frequent read kind */
#define ETHR_RWMTX_R_FLG__ (((long) 1) << 28)
-#define ETHR_RWMTX_R_PEND_UNLCK_MASK__ (ETHR_RWMTX_R_FLG__ - 1)
-#define ETHR_RWMTX_R_MASK__ (ETHR_RWMTX_R_WAIT_FLG__ - 1)
+#define ETHR_RWMTX_R_ABRT_UNLCK_FLG__ (((long) 1) << 27)
+#define ETHR_RWMTX_R_PEND_UNLCK_MASK__ (ETHR_RWMTX_R_ABRT_UNLCK_FLG__ - 1)
/* normal kind */
#define ETHR_RWMTX_RS_MASK__ (ETHR_RWMTX_R_WAIT_FLG__ - 1)
@@ -91,6 +107,12 @@ struct ethr_mutex_base_ {
#ifdef ETHR_MTX_HARD_DEBUG_WSQ
int ws;
#endif
+#ifdef ETHR_MTX_CHK_EXCL
+ ethr_atomic_t exclusive;
+#endif
+#ifdef ETHR_MTX_CHK_NON_EXCL
+ ethr_atomic_t non_exclusive;
+#endif
#ifdef ETHR_MTX_HARD_DEBUG_LFS
ethr_atomic_t hdbg_lfs;
#endif
@@ -344,6 +366,116 @@ do { \
#define ETHR_MTX_HARD_DEBUG_FENCE_INIT(X)
#endif
+#ifdef ETHR_MTX_CHK_EXCL
+
+#if !defined(ETHR_DEBUG) && defined(__GNUC__)
+#warning "check exclusive is enabled"
+#endif
+
+# define ETHR_MTX_CHK_EXCL_INIT__(MTXB) \
+ ethr_atomic_init(&(MTXB)->exclusive, 0)
+
+# define ETHR_MTX_CHK_EXCL_IS_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if (!ethr_atomic_read(&(MTXB)->exclusive)) \
+ ethr_assert_failed(__FILE__, __LINE__, __func__,\
+ "is exclusive"); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_IS_NOT_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if (ethr_atomic_read(&(MTXB)->exclusive)) \
+ ethr_assert_failed(__FILE__, __LINE__, __func__,\
+ "is not exclusive"); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_SET_EXCL(MTXB) \
+do { \
+ ETHR_MTX_CHK_EXCL_IS_NOT_EXCL((MTXB)); \
+ ethr_atomic_set(&(MTXB)->exclusive, 1); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_UNSET_EXCL(MTXB) \
+do { \
+ ETHR_MTX_CHK_EXCL_IS_EXCL((MTXB)); \
+ ethr_atomic_set(&(MTXB)->exclusive, 0); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+
+#ifdef ETHR_MTX_CHK_NON_EXCL
+
+#if !defined(ETHR_DEBUG) && defined(__GNUC__)
+#warning "check non-exclusive is enabled"
+#endif
+
+# define ETHR_MTX_CHK_NON_EXCL_INIT__(MTXB) \
+ ethr_atomic_init(&(MTXB)->non_exclusive, 0)
+# define ETHR_MTX_CHK_EXCL_IS_NON_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if (!ethr_atomic_read(&(MTXB)->non_exclusive)) \
+ ethr_assert_failed(__FILE__, __LINE__, __func__,\
+ "is non-exclusive"); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if (ethr_atomic_read(&(MTXB)->non_exclusive)) \
+ ethr_assert_failed(__FILE__, __LINE__, __func__,\
+ "is not non-exclusive"); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ ethr_atomic_inc(&(MTXB)->non_exclusive); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL_NO(MTXB, NO) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ ethr_atomic_add(&(MTXB)->non_exclusive, (NO)); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_CHK_EXCL_UNSET_NON_EXCL(MTXB) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ ethr_atomic_dec(&(MTXB)->non_exclusive); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+#else
+# define ETHR_MTX_CHK_NON_EXCL_INIT__(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL_NO(MTXB, NO)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_UNSET_NON_EXCL(MTXB)
+#endif
+
+#else
+# define ETHR_MTX_CHK_EXCL_INIT__(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_NOT_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_SET_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_UNSET_EXCL(MTXB)
+# define ETHR_MTX_CHK_NON_EXCL_INIT__(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL_NO(MTXB, NO)
+# define ETHR_MTX_CHK_EXCL_SET_NON_EXCL(MTXB)
+# define ETHR_MTX_CHK_EXCL_UNSET_NON_EXCL(MTXB)
+#endif
+
+# define ETHR_MTX_CHK_EXCL_INIT(MTXB) \
+do { \
+ ETHR_MTX_CHK_EXCL_INIT__((MTXB)); \
+ ETHR_MTX_CHK_NON_EXCL_INIT__((MTXB)); \
+} while (0)
+
+
#ifdef ETHR_USE_OWN_MTX_IMPL__
#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_MAX 2000
@@ -369,6 +501,11 @@ ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
act = ethr_atomic_cmpxchg_acqb(&mtx->mtxb.flgs, ETHR_RWMTX_W_FLG__, 0);
res = (act == 0) ? 0 : EBUSY;
+#ifdef ETHR_MTX_CHK_EXCL
+ if (res == 0)
+ ETHR_MTX_CHK_EXCL_SET_EXCL(&mtx->mtxb);
+#endif
+
ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(&mtx->mtxb, res);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
@@ -386,6 +523,8 @@ ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
if (act != 0)
ethr_mutex_lock_wait__(mtx, act);
+ ETHR_MTX_CHK_EXCL_SET_EXCL(&mtx->mtxb);
+
ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&mtx->mtxb);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
@@ -400,6 +539,8 @@ ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(&mtx->mtxb);
+ ETHR_MTX_CHK_EXCL_UNSET_EXCL(&mtx->mtxb);
+
act = ethr_atomic_cmpxchg_relb(&mtx->mtxb.flgs, 0, ETHR_RWMTX_W_FLG__);
if (act != ETHR_RWMTX_W_FLG__)
ethr_mutex_unlock_wake__(mtx, act);
diff --git a/erts/include/internal/i386/atomic.h b/erts/include/internal/i386/atomic.h
index f28258059f..52d01aab32 100644
--- a/erts/include/internal/i386/atomic.h
+++ b/erts/include/internal/i386/atomic.h
@@ -167,15 +167,52 @@ ethr_native_atomic_xchg(ethr_native_atomic_t *var, long val)
* Atomic ops with at least specified barriers.
*/
-#define ethr_native_atomic_read_acqb ethr_native_atomic_read
-#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+ long val;
+#if defined(__x86_64__) || !defined(ETHR_PRE_PENTIUM4_COMPAT)
+ val = var->counter;
+#else
+ val = ethr_native_atomic_add_return(var, 0);
+#endif
+ __asm__ __volatile__("" : : : "memory");
+ return val;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long i)
+{
+ __asm__ __volatile__("" : : : "memory");
#if defined(__x86_64__) || !defined(ETHR_PRE_PENTIUM4_COMPAT)
-#define ethr_native_atomic_set_relb ethr_native_atomic_set
+ var->counter = i;
#else
-#define ethr_native_atomic_set_relb ethr_native_atomic_xchg
+ (void) ethr_native_atomic_xchg(var, i);
#endif
-#define ethr_native_atomic_dec_relb ethr_native_atomic_dec
-#define ethr_native_atomic_dec_return_relb ethr_native_atomic_dec_return
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_inc_return(var);
+ __asm__ __volatile__("" : : : "memory");
+ return res;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
+{
+ __asm__ __volatile__("" : : : "memory");
+ ethr_native_atomic_dec(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
+{
+ __asm__ __volatile__("" : : : "memory");
+ return ethr_native_atomic_dec_return(var);
+}
+
#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
diff --git a/erts/include/internal/sparc32/atomic.h b/erts/include/internal/sparc32/atomic.h
index 2a995d4465..2da6472393 100644
--- a/erts/include/internal/sparc32/atomic.h
+++ b/erts/include/internal/sparc32/atomic.h
@@ -176,38 +176,59 @@ ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long old)
* Atomic ops with at least specified barriers.
*/
+/* TODO: relax acquire barriers */
+
static ETHR_INLINE long
ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
{
long res = ethr_native_atomic_read(var);
- __asm__ __volatile__("membar #StoreLoad|#StoreStore");
+ __asm__ __volatile__("membar #LoadLoad|#LoadStore|#StoreLoad|#StoreStore" : : : "memory");
return res;
}
static ETHR_INLINE void
ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long i)
{
- __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ __asm__ __volatile__("membar #LoadStore|#StoreStore" : : : "memory");
ethr_native_atomic_set(var, i);
}
+static ETHR_INLINE long
+ethr_native_atomic_inc_return_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_inc_return(var);
+ __asm__ __volatile__("membar #LoadLoad|#LoadStore" : : : "memory");
+ return res;
+}
+
static ETHR_INLINE void
ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
{
- __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ __asm__ __volatile__("membar #LoadStore|#StoreStore" : : : "memory");
ethr_native_atomic_dec(var);
}
static ETHR_INLINE long
ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
{
- __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ __asm__ __volatile__("membar #LoadStore|#StoreStore" : : : "memory");
return ethr_native_atomic_dec_return(var);
}
-#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
-#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
-#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_acqb(ethr_native_atomic_t *var, long new, long old)
+{
+ long res = ethr_native_atomic_cmpxchg(var, new, old);
+ __asm__ __volatile__("membar #LoadLoad|#LoadStore" : : : "memory");
+ return res;
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_relb(ethr_native_atomic_t *var, long new, long old)
+{
+ __asm__ __volatile__("membar #LoadStore|#StoreStore" : : : "memory");
+ return ethr_native_atomic_cmpxchg(var, new, old);
+}
#endif /* ETHR_TRY_INLINE_FUNCS */
diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c
index 78323b62a3..c5738c3d77 100644
--- a/erts/lib_src/common/ethr_mutex.c
+++ b/erts/lib_src/common/ethr_mutex.c
@@ -205,9 +205,14 @@ static void hard_debug_chk_q__(struct ethr_mutex_base_ *, int);
#ifdef ETHR_USE_OWN_RWMTX_IMPL__
static void
+rwmutex_transfer_read_lock(ethr_rwmutex *rwmtx,
+ long initial,
+ int q_locked);
+static void
rwmutex_unlock_wake(ethr_rwmutex *rwmtx,
int have_w,
- long initial);
+ long initial,
+ int transfer_read_lock);
static int
rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
long initial,
@@ -334,7 +339,7 @@ rwmutex_freqread_rdrs_read(ethr_rwmutex *rwmtx, int ix)
ETHR_ASSERT(res >= 0);
break;
case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ:
- ETHR_ASSERT(res == 0 || res == 1);
+ ETHR_ASSERT(ix == 0 ? res >= 0 : (res == 0 || res == 1));
break;
default:
ETHR_ASSERT(0);
@@ -400,6 +405,7 @@ event_wait(struct ethr_mutex_base_ *mtxb,
int locked = 0;
long act;
int need_try_complete_runlock = 0;
+ int transfer_read_lock = 0;
/* Need to enqueue and wait... */
@@ -444,8 +450,8 @@ event_wait(struct ethr_mutex_base_ *mtxb,
while (1) {
long new, exp = act;
- int freqread_tryrlock = 0;
need_try_complete_runlock = 0;
+ transfer_read_lock = 0;
if (type == ETHR_RWMTX_W_WAIT_FLG__) {
if (is_freq_read && act == ETHR_RWMTX_R_FLG__)
@@ -465,14 +471,11 @@ event_wait(struct ethr_mutex_base_ *mtxb,
new = act + 1; /* Try to get it */
}
else {
- if (act & ~ETHR_RWMTX_R_FLG__)
- new = act | ETHR_RWMTX_R_WAIT_FLG__;
- else { /* Try to get it */
- ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
- rwmutex_freqread_rdrs_inc(rwmtx, tse);
- ETHR_MEMORY_BARRIER;
- new = act | ETHR_RWMTX_R_FLG__;
- freqread_tryrlock = 1;
+ new = act | ETHR_RWMTX_R_WAIT_FLG__;
+ if ((act & (ETHR_RWMTX_W_FLG__
+ | ETHR_RWMTX_W_WAIT_FLG__)) == 0) {
+ /* Transfer read lock to this thread. */
+ transfer_read_lock = 1;
}
}
}
@@ -488,24 +491,6 @@ event_wait(struct ethr_mutex_base_ *mtxb,
goto done;
}
}
-
- if (freqread_tryrlock) {
- ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
-
- /* We didn't set ETHR_RWMTX_R_FLG__, however someone
- else might have */
- if (act == ETHR_RWMTX_R_FLG__)
- goto done; /* Got it by help from someone else */
-
- ETHR_ASSERT((act & ETHR_RWMTX_WAIT_FLGS__) == 0);
- /*
- * We know that no waiter flags have been set, i.e.,
- * we cannot get into a situation where we need to wake
- * someone up here. Just restore the readers counter
- * and do it over again...
- */
- rwmutex_freqread_rdrs_dec(rwmtx, tse);
- }
}
/* Enqueue */
@@ -535,20 +520,36 @@ event_wait(struct ethr_mutex_base_ *mtxb,
/* Wait */
locked = 0;
- ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
- if (need_try_complete_runlock) {
+ ETHR_ASSERT(!(transfer_read_lock && need_try_complete_runlock));
+
+ if (transfer_read_lock) {
ETHR_ASSERT(((ethr_rwmutex *) mtxb)->type
!= ETHR_RWMUTEX_TYPE_NORMAL);
/*
- * We were the only one in queue when we enqueued, and it
- * was seemingly read locked. We need to try to complete a
- * runlock otherwise we might be hanging forever. If the
- * runlock could be completed we will be dequeued and
- * woken by ourselves.
+ * We are the only one in the queue and we are not write
+ * locked; rwmutex_transfer_read_lock() will:
+ * - transfer a read lock to us (since we're first in q)
+ * - unlock the Q-lock
*/
- rwmutex_try_complete_runlock((ethr_rwmutex *) mtxb,
- act, tse, 0, 1, 0);
+ rwmutex_transfer_read_lock(((ethr_rwmutex *) mtxb), act, 1);
+ }
+ else {
+ ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
+
+ if (need_try_complete_runlock) {
+ ETHR_ASSERT(((ethr_rwmutex *) mtxb)->type
+ != ETHR_RWMUTEX_TYPE_NORMAL);
+ /*
+ * We were the only one in queue when we enqueued, and it
+ * was seemingly read locked. We need to try to complete a
+ * runlock otherwise we might be hanging forever. If the
+ * runlock could be completed we will be dequeued and
+ * woken by ourselves.
+ */
+ rwmutex_try_complete_runlock((ethr_rwmutex *) mtxb,
+ act, tse, 0, 1, 0);
+ }
}
while (1) {
@@ -653,8 +654,6 @@ write_lock_wait(struct ethr_mutex_base_ *mtxb,
ethr_ts_event *tse = NULL;
int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
int res;
- int freq_read_size = -1;
- int freq_read_start_ix = -1;
ETHR_ASSERT(!is_freq_read || is_rwmtx);
@@ -666,44 +665,23 @@ write_lock_wait(struct ethr_mutex_base_ *mtxb,
*/
while (1) {
- long exp;
-
while (act != 0) {
if (is_freq_read && act == ETHR_RWMTX_R_FLG__) {
ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ scnt--;
if (!tse)
tse = ethr_get_ts_event();
- if (freq_read_size < 0) {
- if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
- freq_read_size = reader_groups_array_size;
- freq_read_start_ix = tse->rgix;
- }
- else {
- freq_read_size = main_threads_array_size;
- freq_read_start_ix = tse->mtix;
- }
- }
- res = check_readers_array(rwmtx,
- freq_read_start_ix,
- freq_read_size);
- scnt--;
- if (res == 0) {
- act = ethr_atomic_read(&mtxb->flgs);
- if (act & ETHR_RWMTX_R_MASK__) {
- res = rwmutex_try_complete_runlock(rwmtx, act,
- tse, 0, 0,
- 1);
- if (res != EBUSY)
- goto done; /* Got it */
- }
- if (scnt <= 0)
- goto chk_spin;
- if (--until_yield == 0) {
- until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
- ETHR_YIELD();
- }
- continue;
+ res = rwmutex_try_complete_runlock(rwmtx, act,
+ tse, 0, 0,
+ 1);
+ if (res != EBUSY)
+ goto done; /* Got it */
+ if (scnt <= 0)
+ goto chk_spin;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ ETHR_YIELD();
}
}
@@ -728,11 +706,9 @@ write_lock_wait(struct ethr_mutex_base_ *mtxb,
scnt--;
}
- exp = act;
-
act = ethr_atomic_cmpxchg_acqb(&mtxb->flgs,
ETHR_RWMTX_W_FLG__,
- exp);
+ 0);
if (act == 0)
goto done; /* Got it */
}
@@ -753,6 +729,7 @@ mtxb_init(struct ethr_mutex_base_ *mtxb,
#ifdef ETHR_MTX_HARD_DEBUG_WSQ
mtxb->ws = 0;
#endif
+ ETHR_MTX_CHK_EXCL_INIT(mtxb);
if (no_spin) {
mtxb->main_scnt = 0;
mtxb->aux_scnt = 0;
@@ -1254,7 +1231,7 @@ ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&mtx->mtxb);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
-
+ ETHR_MTX_CHK_EXCL_SET_EXCL(&mtx->mtxb);
tse->udata = udata;
ethr_leave_ts_event(tse);
return 0;
@@ -1499,7 +1476,62 @@ int check_readers_array(ethr_rwmutex *rwmtx,
return 0;
}
-static ETHR_INLINE void
+static void
+rwmutex_freqread_rdrs_dec_chk_wakeup(ethr_rwmutex *rwmtx,
+ ethr_ts_event *tse,
+ long initial)
+{
+ long act = initial;
+
+ if ((act & (ETHR_RWMTX_W_FLG__|
+ ETHR_RWMTX_R_ABRT_UNLCK_FLG__)) == 0) {
+ if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ if (act & ETHR_RWMTX_R_PEND_UNLCK_MASK__) {
+ /*
+ * We *need* to try to complete the runlock.
+ * A writer that just enqueued (not seen by us
+ * in flag field) may depend on someone else
+ * completing the runlock. We just took over
+ * that responsibilty since we modified reader
+ * groups.
+ */
+ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0);
+ }
+ }
+ else if ((act & ETHR_RWMTX_WAIT_FLGS__) == ETHR_RWMTX_R_WAIT_FLG__)
+ rwmutex_transfer_read_lock(rwmtx, act, 0);
+ else if ((act & ETHR_RWMTX_WAIT_FLGS__) == ETHR_RWMTX_W_WAIT_FLG__)
+ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0);
+ else {
+ /*
+ * Don't know if we got readers or writers
+ * first in queue; need to peek
+ */
+ ETHR_MTX_Q_LOCK(&rwmtx->mtxb.qlck);
+ if (!rwmtx->mtxb.q)
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ else if (is_w_waiter(rwmtx->mtxb.q)) {
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ if ((act & ETHR_RWMTX_W_FLG__) == 0)
+ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0);
+ }
+ else {
+ /*
+ * rwmutex_transfer_read_lock() will
+ * unlock Q lock.
+ */
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ if (act & ETHR_RWMTX_W_FLG__)
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ else
+ rwmutex_transfer_read_lock(rwmtx, act, 1);
+ }
+ }
+ }
+}
+
+static void
rwmutex_freqread_restore_failed_tryrlock(ethr_rwmutex *rwmtx,
ethr_ts_event *tse)
{
@@ -1509,24 +1541,11 @@ rwmutex_freqread_restore_failed_tryrlock(ethr_rwmutex *rwmtx,
*/
act = rwmutex_freqread_rdrs_dec_read(rwmtx, tse);
- ETHR_WRITE_MEMORY_BARRIER;
+ ETHR_MEMORY_BARRIER;
if (act == 0) {
-
-#ifndef ETHR_WRITE_MEMORY_BARRIER_IS_FULL
- ETHR_READ_MEMORY_BARRIER;
-#endif
-
act = ethr_atomic_read(&rwmtx->mtxb.flgs);
-
- if ((act & ETHR_RWMTX_W_FLG__) == 0
- && act & (ETHR_RWMTX_WAIT_FLGS__|ETHR_RWMTX_R_PEND_UNLCK_MASK__)) {
- /*
- * We either got waiters, or someone else trying
- * to read unlock which we might have to help.
- */
- rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 1, 0);
- }
+ rwmutex_freqread_rdrs_dec_chk_wakeup(rwmtx, tse, act);
}
}
@@ -1542,12 +1561,16 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
long act = initial;
int six, res, length;
+ ETHR_ASSERT((act & ETHR_RWMTX_W_FLG__) == 0);
+
+ if (act & ETHR_RWMTX_R_ABRT_UNLCK_FLG__)
+ return try_write_lock ? EBUSY : 0;
+
tse_tmp = tse;
if (!tse_tmp)
tse_tmp = ethr_get_ts_event();
- if ((act & ETHR_RWMTX_WAIT_FLGS__)
- && (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0)
+ if ((act & ETHR_RWMTX_WAIT_FLGS__) && (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0)
goto check_waiters;
if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
@@ -1569,14 +1592,21 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
if (check_before_try) {
res = check_readers_array(rwmtx, six, length);
+
+ ETHR_MEMORY_BARRIER;
+
if (res == EBUSY)
return try_write_lock ? EBUSY : 0;
}
+ restart:
+
while (1) {
long exp = act;
long new = act+1;
+ ETHR_ASSERT((act & ETHR_RWMTX_R_ABRT_UNLCK_FLG__) == 0);
+
ETHR_ASSERT((act & ETHR_RWMTX_R_PEND_UNLCK_MASK__)
< ETHR_RWMTX_R_PEND_UNLCK_MASK__);
@@ -1585,8 +1615,10 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
act = new;
break;
}
+
if (!try_write_lock) {
- if (act == ETHR_RWMTX_W_FLG__ || act == 0)
+ if (act == 0 || (act & (ETHR_RWMTX_W_FLG__
+ | ETHR_RWMTX_R_ABRT_UNLCK_FLG__)))
return 0;
if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
if ((act & ETHR_RWMTX_R_FLG__) == 0)
@@ -1601,33 +1633,50 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
else {
if (act == 0)
goto tryrwlock;
- if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_WAIT_FLGS__))
+ if (act & (ETHR_RWMTX_W_FLG__
+ | ETHR_RWMTX_R_ABRT_UNLCK_FLG__))
return EBUSY;
}
}
res = check_readers_array(rwmtx, six, length);
- if (res == EBUSY) {
- act = ethr_atomic_dec_read(&rwmtx->mtxb.flgs);
- if (act & ETHR_RWMTX_R_MASK__)
- return try_write_lock ? EBUSY : 0;
- }
- else {
- while (1) {
- long exp = act;
- long new = act;
- new &= ~ETHR_RWMTX_R_FLG__;
- new--;
- ETHR_ASSERT(act & ETHR_RWMTX_R_PEND_UNLCK_MASK__);
+ ETHR_MEMORY_BARRIER;
- act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
- if (exp == act) {
- if (new & ETHR_RWMTX_R_PEND_UNLCK_MASK__)
- return try_write_lock ? EBUSY : 0;
- act = new;
- break;
+ ETHR_ASSERT((act & ETHR_RWMTX_W_FLG__) == 0);
+
+ while (1) {
+ int finished_abort = 0;
+ long exp = act;
+ long new = act;
+
+ new--;
+ if (act & ETHR_RWMTX_R_ABRT_UNLCK_FLG__) {
+ if ((new & ETHR_RWMTX_R_PEND_UNLCK_MASK__) == 0) {
+ new &= ~ETHR_RWMTX_R_ABRT_UNLCK_FLG__;
+ finished_abort = 1;
}
+ ETHR_ASSERT(act & ETHR_RWMTX_R_FLG__);
+ }
+ else if ((act & ETHR_RWMTX_R_FLG__) && res != EBUSY) {
+ new &= ~ETHR_RWMTX_R_FLG__;
+ }
+
+ ETHR_ASSERT(act & ETHR_RWMTX_R_PEND_UNLCK_MASK__);
+
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (exp == act) {
+ act = new;
+ if (act & ETHR_RWMTX_W_FLG__)
+ return try_write_lock ? EBUSY : 0;
+ if (finished_abort && (act & ETHR_RWMTX_WAIT_FLGS__))
+ goto restart;
+ if (act & (ETHR_RWMTX_R_FLG__
+ | ETHR_RWMTX_R_ABRT_UNLCK_FLG__
+ | ETHR_RWMTX_R_PEND_UNLCK_MASK__))
+ return try_write_lock ? EBUSY : 0;
+ /* Read unlock completed */
+ break;
}
}
@@ -1637,12 +1686,9 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
* to write lock it).
*/
- if (act & ETHR_RWMTX_W_FLG__)
- return try_write_lock ? EBUSY : 0;
-
if (act & ETHR_RWMTX_WAIT_FLGS__) {
check_waiters:
- rwmutex_unlock_wake(rwmtx, 0, act);
+ rwmutex_unlock_wake(rwmtx, 0, act, 0);
return try_write_lock ? EBUSY : 0;
}
@@ -1670,7 +1716,7 @@ rwmutex_incdec_restore_failed_tryrlock(ethr_rwmutex *rwmtx)
act = ethr_atomic_dec_read(&rwmtx->mtxb.flgs);
if ((act & ETHR_RWMTX_WAIT_FLGS__)
&& (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0) {
- rwmutex_unlock_wake(rwmtx, 0, act);
+ rwmutex_unlock_wake(rwmtx, 0, act, 0);
}
}
@@ -1700,7 +1746,7 @@ rwmutex_normal_rlock_wait(ethr_rwmutex *rwmtx,
#endif
while (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
- if (scnt >= 0) {
+ if (scnt <= 0) {
tse = ethr_get_ts_event();
if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) {
event_wait(&rwmtx->mtxb, tse, scnt,
@@ -1736,10 +1782,83 @@ rwmutex_normal_rlock_wait(ethr_rwmutex *rwmtx,
static void
rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx,
- ethr_ts_event *tse,
- long initial)
+ ethr_ts_event *tse);
+
+static int
+rwmutex_freqread_rlock(ethr_rwmutex *rwmtx, ethr_ts_event *tse, int trylock)
{
- long act = initial;
+ int res = 0;
+ long act;
+
+ rwmutex_freqread_rdrs_inc(rwmtx, tse);
+
+ ETHR_MEMORY_BARRIER;
+
+ act = ethr_atomic_read_acqb(&rwmtx->mtxb.flgs);
+
+ if (act != ETHR_RWMTX_R_FLG__) {
+ int wake_other_readers;
+
+ while (1) {
+ long exp, new;
+
+ wake_other_readers = 0;
+
+ if (act == 0)
+ new = act | ETHR_RWMTX_R_FLG__;
+ else if (act == ETHR_RWMTX_R_FLG__)
+ break; /* Got it */
+ else if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
+ rwmutex_freqread_restore_failed_tryrlock(rwmtx, tse);
+ if (trylock)
+ res = EBUSY;
+ else
+ rwmutex_freqread_rlock_wait(rwmtx, tse);
+ break;
+ }
+ else if (act & ETHR_RWMTX_R_ABRT_UNLCK_FLG__) {
+ if ((act & ETHR_RWMTX_R_FLG__) == 0)
+ ETHR_FATAL_ERROR__(EFAULT);
+ /*
+ * An aborted runlock, not write locked, and no write
+ * waiters, i.e., we got it...
+ */
+ if (act & ETHR_RWMTX_R_WAIT_FLG__)
+ wake_other_readers = 1;
+ break;
+ }
+ else {
+ new = act | ETHR_RWMTX_R_FLG__;
+ if (act & ETHR_RWMTX_R_PEND_UNLCK_MASK__) {
+ /*
+ * Someone is doing tryrwlock (no writer and no
+ * write waiters); we will try to abort that...
+ */
+ new |= ETHR_RWMTX_R_ABRT_UNLCK_FLG__;
+ }
+
+ if (act & ETHR_RWMTX_R_WAIT_FLG__)
+ wake_other_readers = 1;
+ }
+
+ exp = act;
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ break;
+ }
+
+ if (wake_other_readers)
+ rwmutex_transfer_read_lock(rwmtx, act, 0);
+ }
+
+ return res;
+}
+
+static void
+rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx,
+ ethr_ts_event *tse)
+{
+ long act;
int scnt, start_scnt;
int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
@@ -1752,12 +1871,10 @@ rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx,
while (1) {
- rwmutex_freqread_restore_failed_tryrlock(rwmtx, tse);
-
act = ethr_atomic_read(&rwmtx->mtxb.flgs);
- while (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
- if (scnt >= 0) {
+ while (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
+ if (scnt <= 0) {
if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) {
event_wait(&rwmtx->mtxb, tse, scnt,
ETHR_RWMTX_R_WAIT_FLG__, 1, 1);
@@ -1773,30 +1890,8 @@ rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx,
scnt--;
}
- rwmutex_freqread_rdrs_inc(rwmtx, tse);
-
- ETHR_MEMORY_BARRIER;
-
- act = ethr_atomic_read(&rwmtx->mtxb.flgs);
-
- if (act == ETHR_RWMTX_R_FLG__)
- return; /* Got it */
-
- while (1) {
- long exp, new;
-
- if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__))
- break; /* Busy (need to restore inc) */
-
- if (act & ETHR_RWMTX_R_FLG__)
- return; /* Got it */
-
- exp = act;
- new = act | ETHR_RWMTX_R_FLG__;
- act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
- if (act == exp)
- return; /* Got it */
- }
+ if (rwmutex_freqread_rlock(rwmtx, tse, 1) != EBUSY)
+ break; /* Got it */
}
}
@@ -1816,14 +1911,23 @@ static ETHR_INLINE void
rwlock_wake_set_flags(ethr_rwmutex *rwmtx, long new_initial, int act_initial)
{
long act, act_mask;
+ int chk_abrt_flg;
+
+ ETHR_MEMORY_BARRIER;
+
if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL) {
/* r pend unlock mask may vary and must be retained */
act_mask = ETHR_RWMTX_R_PEND_UNLCK_MASK__;
+ if (new_initial & ETHR_RWMTX_R_FLG__)
+ chk_abrt_flg = 1;
+ else
+ chk_abrt_flg = 0;
}
else {
#ifdef ETHR_RLOCK_WITH_INC_DEC
/* rs mask may vary and must be retained */
act_mask = ETHR_RWMTX_RS_MASK__;
+ chk_abrt_flg = 0;
#else
/* rs mask always zero */
ETHR_ASSERT((act_initial & ETHR_RWMTX_RS_MASK__) == 0);
@@ -1836,6 +1940,8 @@ rwlock_wake_set_flags(ethr_rwmutex *rwmtx, long new_initial, int act_initial)
while (1) {
long exp = act;
long new = new_initial + (act & act_mask);
+ if (chk_abrt_flg && (act & act_mask))
+ new |= ETHR_RWMTX_R_ABRT_UNLCK_FLG__;
act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
if (act == exp)
break;
@@ -1883,6 +1989,14 @@ dbg_unlock_wake(ethr_rwmutex *rwmtx,
exp |= ETHR_RWMTX_R_WAIT_FLG__;
if (rwmtx->rq_end->next != rwmtx->mtxb.q)
exp |= ETHR_RWMTX_W_WAIT_FLG__;
+ else if (exp == ETHR_RWMTX_R_WAIT_FLG__) {
+ if (!have_w) {
+ if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL)
+ imask |= ETHR_RWMTX_R_FLG__;
+ else
+ imask |= ETHR_RWMTX_RS_MASK__;
+ }
+ }
act = ethr_atomic_read(&rwmtx->mtxb.flgs);
ETHR_ASSERT((exp & ~imask) == (act & ~imask));
@@ -1894,41 +2008,83 @@ dbg_unlock_wake(ethr_rwmutex *rwmtx,
#endif
static void
-rwmutex_unlock_wake(ethr_rwmutex *rwmtx, int have_w, long initial)
+rwmutex_transfer_read_lock(ethr_rwmutex *rwmtx, long initial, int q_locked)
+{
+ long act = initial;
+
+ if (!q_locked) {
+ ethr_ts_event *tse;
+ ETHR_ASSERT(initial & ETHR_RWMTX_R_WAIT_FLG__);
+ ETHR_ASSERT((initial & ETHR_RWMTX_W_FLG__) == 0);
+ ETHR_MTX_Q_LOCK(&rwmtx->mtxb.qlck);
+
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ tse = rwmtx->mtxb.q;
+ if ((act & ETHR_RWMTX_W_FLG__) || !tse || is_w_waiter(tse)) {
+ /* Someone else woke the readers up... */
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ return;
+ }
+ }
+
+ rwmutex_unlock_wake(rwmtx, 0, initial, 1);
+}
+
+static void
+rwmutex_unlock_wake(ethr_rwmutex *rwmtx, int have_w, long initial,
+ int transfer_read_lock)
{
long new, act = initial;
ethr_ts_event *tse;
- if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
- if (!have_w)
- return;
- else {
- while ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
- long exp = act;
- new = exp & ~ETHR_RWMTX_W_FLG__;
- act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
- if (act == exp)
- return;
+ if (transfer_read_lock) {
+ /*
+ * - Q already locked
+ * - Got R waiters first in Q
+ * - Not W locked
+ */
+ tse = rwmtx->mtxb.q;
+
+ ETHR_ASSERT(act & ETHR_RWMTX_R_WAIT_FLG__);
+ ETHR_ASSERT((act & (ETHR_RWMTX_W_FLG__)) == 0);
+ ETHR_ASSERT(tse && !is_w_waiter(tse));
+ }
+ else {
+
+ if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ if (!have_w)
+ return;
+ else {
+ while ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ long exp = act;
+ new = exp & ~ETHR_RWMTX_W_FLG__;
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ return;
+ }
}
}
- }
- ETHR_MTX_Q_LOCK(&rwmtx->mtxb.qlck);
- tse = rwmtx->mtxb.q;
+ ETHR_MTX_Q_LOCK(&rwmtx->mtxb.qlck);
+ tse = rwmtx->mtxb.q;
- if (!have_w) {
- if (!tse) {
+ if (!have_w) {
+ if (!tse) {
#ifdef ETHR_DEBUG
- act = ethr_atomic_read(&rwmtx->mtxb.flgs);
- ETHR_ASSERT((act & ETHR_RWMTX_WAIT_FLGS__) == 0);
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ ETHR_ASSERT((act & ETHR_RWMTX_WAIT_FLGS__) == 0);
#endif
- goto already_served;
- }
- act = ethr_atomic_read(&rwmtx->mtxb.flgs);
- if (act & ~ETHR_RWMTX_WAIT_FLGS__) {
- already_served:
- ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
- return;
+ goto already_served;
+ }
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ if (act == (ETHR_RWMTX_R_WAIT_FLG__|ETHR_RWMTX_R_FLG__)) {
+ ETHR_ASSERT(tse && !is_w_waiter(tse));
+ }
+ else if (act & ~ETHR_RWMTX_WAIT_FLGS__) {
+ already_served:
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ return;
+ }
}
}
@@ -1988,6 +2144,7 @@ rwmutex_unlock_wake(ethr_rwmutex *rwmtx, int have_w, long initial)
rwmutex_freqread_rdrs_add(rwmtx, type, ix, wrs);
}
}
+
new = ETHR_RWMTX_R_FLG__;
}
@@ -1995,6 +2152,7 @@ rwmutex_unlock_wake(ethr_rwmutex *rwmtx, int have_w, long initial)
new |= ETHR_RWMTX_W_WAIT_FLG__;
rwlock_wake_set_flags(rwmtx, new, act);
+
wake_readers(rwmtx, rs);
}
}
@@ -2225,39 +2383,19 @@ ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
ethr_ts_event *tse = ethr_get_ts_event();
-
- rwmutex_freqread_rdrs_inc(rwmtx, tse);
-
- ETHR_MEMORY_BARRIER;
-
- act = ethr_atomic_read_acqb(&rwmtx->mtxb.flgs);
-
- if (act != ETHR_RWMTX_R_FLG__) {
- while (1) {
- long exp, new;
-
- if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
- rwmutex_freqread_restore_failed_tryrlock(rwmtx, tse);
- res = EBUSY;
- break;
- }
-
- if (act & ETHR_RWMTX_R_FLG__)
- break;
-
- exp = act;
- new = act | ETHR_RWMTX_R_FLG__;
- act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, new, exp);
- if (act == exp)
- break;
- }
- }
-
+ res = rwmutex_freqread_rlock(rwmtx, tse, 1);
ethr_leave_ts_event(tse);
break;
}
}
+#ifdef ETHR_MTX_CHK_EXCL
+ if (res == 0) {
+ ETHR_MTX_CHK_EXCL_SET_NON_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_IS_NOT_EXCL(&rwmtx->mtxb);
+ }
+#endif
+
ETHR_MTX_HARD_DEBUG_LFS_TRYRLOCK(&rwmtx->mtxb, res);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
@@ -2286,9 +2424,8 @@ ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
while (1) {
act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, exp+1, exp);
- if (act == exp) {
+ if (act == exp)
break;
- }
if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
rwmutex_normal_rlock_wait(rwmtx, act);
@@ -2303,38 +2440,14 @@ ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
ethr_ts_event *tse = ethr_get_ts_event();
-
- rwmutex_freqread_rdrs_inc(rwmtx, tse);
-
- ETHR_MEMORY_BARRIER;
-
- act = ethr_atomic_read_acqb(&rwmtx->mtxb.flgs);
-
- if (act != ETHR_RWMTX_R_FLG__) {
- while (1) {
- long exp, new;
-
- if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
- rwmutex_freqread_rlock_wait(rwmtx, tse, act);
- break;
- }
-
- if (act & ETHR_RWMTX_R_FLG__)
- break;
-
- exp = act;
- new = act | ETHR_RWMTX_R_FLG__;
- act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, new, exp);
- if (act == exp)
- break;
- }
- }
-
+ rwmutex_freqread_rlock(rwmtx, tse, 0);
ethr_leave_ts_event(tse);
break;
}
}
+ ETHR_MTX_CHK_EXCL_SET_NON_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_IS_NOT_EXCL(&rwmtx->mtxb);
ETHR_MTX_HARD_DEBUG_LFS_RLOCK(&rwmtx->mtxb);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
}
@@ -2344,6 +2457,8 @@ ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
{
long act;
+ ETHR_MTX_CHK_EXCL_IS_NOT_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_UNSET_NON_EXCL(&rwmtx->mtxb);
ETHR_ASSERT(!ethr_not_inited__);
ETHR_ASSERT(rwmtx);
ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
@@ -2357,7 +2472,7 @@ ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
if ((act & ETHR_RWMTX_WAIT_FLGS__)
&& (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0) {
ETHR_ASSERT((act & ETHR_RWMTX_W_FLG__) == 0);
- rwmutex_unlock_wake(rwmtx, 0, act);
+ rwmutex_unlock_wake(rwmtx, 0, act, 0);
}
break;
@@ -2369,21 +2484,12 @@ ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
ETHR_ASSERT(act >= 0);
- ETHR_WRITE_MEMORY_BARRIER;
+ ETHR_MEMORY_BARRIER;
if (act == 0) {
-
-#ifndef ETHR_WRITE_MEMORY_BARRIER_IS_FULL
- ETHR_READ_MEMORY_BARRIER;
-#endif
act = ethr_atomic_read(&rwmtx->mtxb.flgs);
-
- if ((act & ETHR_RWMTX_W_FLG__) == 0
- && (act & (ETHR_RWMTX_WAIT_FLGS__
- | ETHR_RWMTX_R_PEND_UNLCK_MASK__))) {
- rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0);
- }
-
+ if (act != ETHR_RWMTX_R_FLG__)
+ rwmutex_freqread_rdrs_dec_chk_wakeup(rwmtx, tse, act);
}
ethr_leave_ts_event(tse);
@@ -2422,25 +2528,31 @@ ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
do {
- if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_WAIT_FLGS__)) {
- res = EBUSY;
- break;
- }
-
- if (act & ETHR_RWMTX_R_MASK__) {
+ if (act == 0)
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__, 0);
+ else if (act == ETHR_RWMTX_R_FLG__) {
res = rwmutex_try_complete_runlock(rwmtx, act, NULL,
0, 1, 1);
break;
}
-
- act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
- ETHR_RWMTX_W_FLG__, 0);
+ else {
+ res = EBUSY;
+ break;
+ }
} while (act != 0);
break;
}
+#ifdef ETHR_MTX_CHK_EXCL
+ if (res == 0) {
+ ETHR_MTX_CHK_EXCL_SET_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(&rwmtx->mtxb);
+ }
+#endif
+
ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(&rwmtx->mtxb, res);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
@@ -2485,6 +2597,8 @@ ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
break;
}
+ ETHR_MTX_CHK_EXCL_SET_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(&rwmtx->mtxb);
ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&rwmtx->mtxb);
ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
@@ -2501,12 +2615,15 @@ ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_IS_NOT_NON_EXCL(&rwmtx->mtxb);
+ ETHR_MTX_CHK_EXCL_UNSET_EXCL(&rwmtx->mtxb);
+
switch (rwmtx->type) {
case ETHR_RWMUTEX_TYPE_NORMAL:
act = ethr_atomic_cmpxchg_relb(&rwmtx->mtxb.flgs,
0, ETHR_RWMTX_W_FLG__);
if (act != ETHR_RWMTX_W_FLG__)
- rwmutex_unlock_wake(rwmtx, 1, act);
+ rwmutex_unlock_wake(rwmtx, 1, act, 0);
break;
case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
@@ -2514,7 +2631,7 @@ ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
act = ethr_atomic_cmpxchg_relb(&rwmtx->mtxb.flgs, 0,
ETHR_RWMTX_W_FLG__);
if (act != ETHR_RWMTX_W_FLG__)
- rwmutex_unlock_wake(rwmtx, 1, act);
+ rwmutex_unlock_wake(rwmtx, 1, act, 0);
break;
}
diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl
index 0cc315e9be..93e27fa8d3 100644
--- a/erts/test/ethread_SUITE.erl
+++ b/erts/test/ethread_SUITE.erl
@@ -171,7 +171,15 @@ max_threads(doc) ->
max_threads(suite) ->
[];
max_threads(Config) ->
- run_case(Config, "max_threads", "").
+ case {os:type(), os:version()} of
+ {{unix,darwin}, {9, _, _}} ->
+ %% For some reason pthread_create() crashes when more
+ %% threads cannot be created, instead of returning an
+ %% error code on our MacOS X Leopard machine...
+ {skipped, "MacOS X Leopard cannot cope with this test..."};
+ _ ->
+ run_case(Config, "max_threads", "")
+ end.
tsd(doc) ->
["Tests thread specific data."];
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index 6322860088..1a767a8197 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -51,7 +51,7 @@ CT_MODULES = \
CT_XML_FILES = $(CT_MODULES:=.xml)
XML_APPLICATION_FILES = ref_man.xml
-XML_REF1_FILES = run_test.xml
+XML_REF1_FILES = ct_run.xml
XML_REF3_FILES = $(CT_XML_FILES)
XML_REF6_FILES = common_test_app.xml
diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml
index 77b0c0c0b7..59151a73ec 100644
--- a/lib/common_test/doc/src/config_file_chapter.xml
+++ b/lib/common_test/doc/src/config_file_chapter.xml
@@ -248,7 +248,7 @@
<p><c>Callback:check_parameter/1</c></p>
<p>The input argument will be passed from Common Test, as defined in the test
- specification or given as an option to <c>run_test</c>.</p>
+ specification or given as an option to <c>ct_run</c> or <c>ct:run_test</c>.</p>
<p>The return value should be any of the following values indicating if given
configuration parameter is valid:</p>
diff --git a/lib/common_test/doc/src/cover_chapter.xml b/lib/common_test/doc/src/cover_chapter.xml
index 6e4f59ef73..377409ed7b 100644
--- a/lib/common_test/doc/src/cover_chapter.xml
+++ b/lib/common_test/doc/src/cover_chapter.xml
@@ -94,10 +94,10 @@
<p>To activate the code coverage support, you simply specify the
name of the cover specification file as you start Common Test.
- This you do either by using the <c>-cover</c> flag with <c>run_test</c>.
+ This you do either by using the <c>-cover</c> flag with <c>ct_run</c>.
Example:</p>
- <p><c>$ run_test -dir $TESTOBJS/db -cover $TESTOBJS/db/config/db.coverspec</c></p>
+ <p><c>$ ct_run -dir $TESTOBJS/db -cover $TESTOBJS/db/config/db.coverspec</c></p>
<p>You may also pass the cover specification file name in a
call to <c>ct:run_test/1</c>, by adding a <c>{cover,CoverSpec}</c>
diff --git a/lib/common_test/doc/src/ct_junit_report.xml b/lib/common_test/doc/src/ct_junit_report.xml
new file mode 100644
index 0000000000..49a40cc1de
--- /dev/null
+++ b/lib/common_test/doc/src/ct_junit_report.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<erlref>
+<header>
+<title>ct_junit_report</title>
+<prepared></prepared>
+<responsible></responsible>
+<docno>1</docno>
+<approved></approved>
+<checked></checked>
+<date></date>
+<rev>A</rev>
+<file>ct_junit_report.xml</file></header>
+<module>ct_junit_report</module>
+<modulesummary>Common Test Framework functions handling test specifications.</modulesummary>
+<description>
+<p>Common Test Framework functions handling test specifications.</p>
+
+ <p>This module creates a junit report of the test run if plugged in
+ as a suite_callback.</p></description>
+<funcs>
+<func>
+<name>init(Opts) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="init-1"/>
+ </desc></func>
+<func>
+<name>post_end_group(Group, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="post_end_group-3"/>
+ </desc></func>
+<func>
+<name>post_end_suite(Suite, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="post_end_suite-3"/>
+ </desc></func>
+<func>
+<name>post_end_tc(TC, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="post_end_tc-3"/>
+ </desc></func>
+<func>
+<name>post_init_group(Group, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="post_init_group-3"/>
+ </desc></func>
+<func>
+<name>post_init_suite(Suite, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="post_init_suite-3"/>
+ </desc></func>
+<func>
+<name>pre_end_group(Group, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="pre_end_group-3"/>
+ </desc></func>
+<func>
+<name>pre_end_suite(Suite, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="pre_end_suite-3"/>
+ </desc></func>
+<func>
+<name>pre_init_group(Group, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="pre_init_group-3"/>
+ </desc></func>
+<func>
+<name>pre_init_suite(Suite, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="pre_init_suite-3"/>
+ </desc></func>
+<func>
+<name>pre_init_tc(TC, Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="pre_init_tc-3"/>
+ </desc></func>
+<func>
+<name>terminate(Config, State) -&gt; term()
+</name>
+<fsummary> </fsummary>
+
+<desc><marker id="terminate-2"/>
+ </desc></func></funcs>
+
+<authors>
+<aname> </aname>
+<email> </email></authors></erlref> \ No newline at end of file
diff --git a/lib/common_test/doc/src/ct_master_chapter.xml b/lib/common_test/doc/src/ct_master_chapter.xml
index 01f8e61d36..f4f0ecad62 100644
--- a/lib/common_test/doc/src/ct_master_chapter.xml
+++ b/lib/common_test/doc/src/ct_master_chapter.xml
@@ -188,7 +188,7 @@
<seealso marker="run_test_chapter#test_specifications">Running Test Suites</seealso>
chapter). The result is that any test specified to run on a node with the same
name as the Common Test node in question (typically <c>ct@somehost</c> if started
- with the <c>run_test</c> program), will be performed. Tests without explicit
+ with the <c>ct_run</c> program), will be performed. Tests without explicit
node association will always be performed too of course!</p>
<note><p>It is recommended that absolute paths are used for log directories,
diff --git a/lib/common_test/doc/src/run_test.xml b/lib/common_test/doc/src/ct_run.xml
index 2f0a94afba..1ab563d74f 100644
--- a/lib/common_test/doc/src/run_test.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -21,7 +21,7 @@
</legalnotice>
- <title>The run_test program</title>
+ <title>The ct_run program</title>
<prepared>Peter Andersson</prepared>
<responsible>Peter Andersson</responsible>
<docno></docno>
@@ -29,18 +29,18 @@
<checked></checked>
<date>2010-04-01</date>
<rev>PA2</rev>
- <file>run_test.xml</file>
+ <file>ct_run.xml</file>
</header>
- <com>run_test</com>
+ <com>ct_run</com>
<comsummary>Program used for starting Common Test from the
OS command line.
</comsummary>
<description>
- <p>The <c>run_test</c> program is automatically installed with Erlang/OTP
+ <p>The <c>ct_run</c> program is automatically installed with Erlang/OTP
and Common Test (please see the Installation chapter in the Common
Test User's Guide for more information). The program accepts a number
- of different start flags. Some flags trigger <c>run_test</c>
+ of different start flags. Some flags trigger <c>ct_run</c>
to start the Common Test application and pass on data to it. Some
flags start an Erlang node prepared for running Common Test in a
particular mode.</p>
@@ -50,20 +50,20 @@
shell (or an Erlang program). Please see the <c>ct</c> man page for
details.</p>
- <p><c>run_test</c> also accepts Erlang emulator flags. These are used
- when <c>run_test</c> calls <c>erl</c> to start the Erlang node
+ <p><c>ct_run</c> also accepts Erlang emulator flags. These are used
+ when <c>ct_run</c> calls <c>erl</c> to start the Erlang node
(making it possible to e.g. add directories to the code server path,
change the cookie on the node, start additional applications, etc).</p>
<p>With the optional flag:</p>
<pre>-erl_args</pre>
- <p>it's possible to divide the options on the <c>run_test</c> command line into
+ <p>it's possible to divide the options on the <c>ct_run</c> command line into
two groups, one that Common Test should process (those preceding <c>-erl_args</c>),
and one it should completely ignore and pass on directly to the emulator
(those following <c>-erl_args</c>). Options preceding <c>-erl_args</c> that Common Test
doesn't recognize, also get passed on to the emulator untouched.
By means of <c>-erl_args</c> the user may specify flags with the same name, but
- with different destinations, on the <c>run_test</c> command line.</p>
+ with different destinations, on the <c>ct_run</c> command line.</p>
<p>If <c>-pa</c> or <c>-pz</c> flags are specified in the Common Test group of options
(preceding <c>-erl_args</c>), relative directories will be converted to
absolute and re-inserted into the code path by Common Test (to avoid
@@ -72,17 +72,17 @@
following <c>-erl_args</c> on the command line. These directories are added
to the code path normally (i.e. on specified form)</p>
- <p>If <c>run_test</c> is called with option:</p>
+ <p>If <c>ct_run</c> is called with option:</p>
<pre>-help</pre>
<p>it prints all valid start flags to stdout.</p>
</description>
- <marker id="run_test"></marker>
+ <marker id="ct_run"></marker>
<section>
<title>Run tests from command line</title>
<pre>
- run_test [-dir TestDir1 TestDir2 .. TestDirN] |
+ ct_run [-dir TestDir1 TestDir2 .. TestDirN] |
[-suite Suite1 Suite2 .. SuiteN
[[-group Group1 Group2 .. GroupN] [-case Case1 Case2 .. CaseN]]]
[-step [config | keep_inactive]]
@@ -110,7 +110,7 @@
<section>
<title>Run tests using test specification</title>
<pre>
- run_test -spec TestSpec1 TestSpec2 .. TestSpecN
+ ct_run -spec TestSpec1 TestSpec2 .. TestSpecN
[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
@@ -136,7 +136,7 @@
<section>
<title>Run tests in web based GUI</title>
<pre>
- run_test -vts [-browser Browser]
+ ct_run -vts [-browser Browser]
[-dir TestDir1 TestDir2 .. TestDirN] |
[-suite Suite [[-group Group] [-case Case]]]
[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
@@ -152,12 +152,12 @@
<section>
<title>Refresh the HTML index files</title>
<pre>
- run_test -refresh_logs [-logdir LogDir] [-basic_html]</pre>
+ ct_run -refresh_logs [-logdir LogDir] [-basic_html]</pre>
</section>
<section>
<title>Run CT in interactive mode</title>
<pre>
- run_test -shell
+ ct_run -shell
[-config ConfigFile1 ConfigFile2 ... ConfigFileN]
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
@@ -166,7 +166,7 @@
<section>
<title>Start a Common Test Master node</title>
<pre>
- run_test -ctmaster</pre>
+ ct_run -ctmaster</pre>
</section>
<section>
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index 7f5144b760..904876ac46 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -63,12 +63,12 @@
<section>
<title>Usage</title>
<p>Event handlers may be installed by means of an <c>event_handler</c>
- start flag (<c>run_test</c>) or option (<c>ct:run_test/1</c>), where the
+ start flag (<c>ct_run</c>) or option (<c>ct:run_test/1</c>), where the
argument specifies the names of one or more event handler modules.
Example:</p>
- <p><c>$ run_test -suite test/my_SUITE -event_handler handlers/my_evh1
+ <p><c>$ ct_run -suite test/my_SUITE -event_handler handlers/my_evh1
handlers/my_evh2 -pa $PWD/handlers</c></p>
- <p>Use the <c><![CDATA[run_test -event_handler_init]]></c> option instead of
+ <p>Use the <c><![CDATA[ct_run -event_handler_init]]></c> option instead of
<c><![CDATA[-event_handler]]></c> to pass start arguments to the event handler
init function.</p>
<p>All event handler modules must have gen_event behaviour. Note also that
diff --git a/lib/common_test/doc/src/install_chapter.xml b/lib/common_test/doc/src/install_chapter.xml
index 828588a673..89c497962d 100644
--- a/lib/common_test/doc/src/install_chapter.xml
+++ b/lib/common_test/doc/src/install_chapter.xml
@@ -34,8 +34,8 @@
<title>General information</title>
<p>The two main interfaces for running tests with Common Test
- are an executable program named run_test and an
- erlang module named <c>ct</c>. The run_test program
+ are an executable program named ct_run and an
+ erlang module named <c>ct</c>. The ct_run program
is compiled for the underlying operating system (e.g. Unix/Linux
or Windows) during the build of the Erlang/OTP system, and is
installed automatically with other executable programs in
@@ -43,22 +43,22 @@
The <c>ct</c> interface functions can be called from the Erlang shell,
or from any Erlang function, on any supported platform.</p>
- <p>A legacy Bourne shell script - also named run_test - exists,
+ <p>A legacy Bourne shell script - named run_test - exists,
which may be manually generated and installed. This script may be used
- instead of the run_test program mentioned above, e.g. if the user
+ instead of the ct_run program mentioned above, e.g. if the user
wishes to modify or customize the Common Test start flags in a simpler
- way than making changes to the run_test C program.</p>
+ way than making changes to the ct_run C program.</p>
<p>The Common Test application is installed with the Erlang/OTP
system and no additional installation step is required to start using
- Common Test by means of the run_test executable program, and/or the interface
+ Common Test by means of the ct_run executable program, and/or the interface
functions in the <c>ct</c> module. If you wish to use the legacy Bourne
- shell script version of run_test, however, this script needs to be
+ shell script version run_test, however, this script needs to be
generated first, according to the instructions below.</p>
<p><note>Before reading on, please note that since Common Test version
1.5, the run_test shell script is no longer required for starting
- tests with Common Test from the OS command line. The run_test
+ tests with Common Test from the OS command line. The ct_run
program (descibed above) is the new recommended command line interface
for Common Test. The shell script exists mainly for legacy reasons and
may not be updated in future releases of Common Test. It may even be removed.
diff --git a/lib/common_test/doc/src/ref_man.xml b/lib/common_test/doc/src/ref_man.xml
index 8be234d979..d5985bb021 100644
--- a/lib/common_test/doc/src/ref_man.xml
+++ b/lib/common_test/doc/src/ref_man.xml
@@ -63,7 +63,7 @@
Server application.</p>
</description>
<xi:include href="common_test_app.xml"/>
- <xi:include href="run_test.xml"/>
+ <xi:include href="ct_run.xml"/>
<!-- If you make modifications in the module list below,
you also need to update CT_MODULES in Makefile. -->
<xi:include href="ct.xml"/>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 1efff25f5b..94fcf6bf01 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -71,7 +71,7 @@
<p>If test suites or help modules include header files stored in other
locations than the test directory, you may specify these include directories
- by means of the <c><![CDATA[-include]]></c> flag with <c><![CDATA[run_test]]></c>,
+ by means of the <c><![CDATA[-include]]></c> flag with <c><![CDATA[ct_run]]></c>,
or the <c><![CDATA[include]]></c> option with <c><![CDATA[ct:run_test/1]]></c>.
In addition to this, an include path may be specified with an OS
environment variable; <c><![CDATA[CT_INCLUDE_PATH]]></c>. Example (bash):</p>
@@ -93,7 +93,7 @@
there instead.</p>
<p>It is possible to disable the automatic compilation feature by using the
- <c><![CDATA[-no_auto_compile]]></c> flag with <c><![CDATA[run_test]]></c>, or
+ <c><![CDATA[-no_auto_compile]]></c> flag with <c><![CDATA[ct_run]]></c>, or
the <c><![CDATA[{auto_compile,false}]]></c> option with
<c><![CDATA[ct:run_test/1]]></c>. With automatic compilation
disabled, the user is responsible for compiling the test suite modules
@@ -108,26 +108,26 @@
<section>
<title>Running tests from the OS command line</title>
- <p>The <c>run_test</c> program can be used for running tests from
+ <p>The <c>ct_run</c> program can be used for running tests from
the OS command line, e.g.
</p>
<list>
- <item><c><![CDATA[run_test -config <configfilenames> -dir <dirs>]]></c></item>
- <item><c><![CDATA[run_test -config <configfilenames> -suite <suiteswithfullpath>]]></c>
+ <item><c><![CDATA[ct_run -config <configfilenames> -dir <dirs>]]></c></item>
+ <item><c><![CDATA[ct_run -config <configfilenames> -suite <suiteswithfullpath>]]></c>
</item>
- <item><c><![CDATA[run_test -userconfig <callbackmodulename> <configfilenames> -suite <suiteswithfullpath>]]></c>
+ <item><c><![CDATA[ct_run -userconfig <callbackmodulename> <configfilenames> -suite <suiteswithfullpath>]]></c>
</item>
- <item><c><![CDATA[run_test -config <configfilenames> -suite <suitewithfullpath>
+ <item><c><![CDATA[ct_run -config <configfilenames> -suite <suitewithfullpath>
-group <groupnames> -case <casenames>]]></c></item>
</list>
<p>Examples:</p>
- <p><c>$ run_test -config $CFGS/sys1.cfg $CFGS/sys2.cfg -dir $SYS1_TEST $SYS2_TEST</c></p>
- <p><c>$ run_test -userconfig ct_config_xml $CFGS/sys1.xml $CFGS/sys2.xml -dir $SYS1_TEST $SYS2_TEST</c></p>
- <p><c>$ run_test -suite $SYS1_TEST/setup_SUITE $SYS2_TEST/config_SUITE</c></p>
- <p><c>$ run_test -suite $SYS1_TEST/setup_SUITE -case start stop</c></p>
- <p><c>$ run_test -suite $SYS1_TEST/setup_SUITE -group installation -case start stop</c></p>
+ <p><c>$ ct_run -config $CFGS/sys1.cfg $CFGS/sys2.cfg -dir $SYS1_TEST $SYS2_TEST</c></p>
+ <p><c>$ ct_run -userconfig ct_config_xml $CFGS/sys1.xml $CFGS/sys2.xml -dir $SYS1_TEST $SYS2_TEST</c></p>
+ <p><c>$ ct_run -suite $SYS1_TEST/setup_SUITE $SYS2_TEST/config_SUITE</c></p>
+ <p><c>$ ct_run -suite $SYS1_TEST/setup_SUITE -case start stop</c></p>
+ <p><c>$ ct_run -suite $SYS1_TEST/setup_SUITE -group installation -case start stop</c></p>
- <p>Other flags that may be used with <c>run_test</c>:</p>
+ <p>Other flags that may be used with <c>ct_run</c>:</p>
<list>
<item><c><![CDATA[-logdir <dir>]]></c>, specifies where the HTML log files are to be written.</item>
<item><c><![CDATA[-label <name_of_test_run>]]></c>, associates the test run with a name that gets printed
@@ -167,20 +167,20 @@
<note><p>Directories passed to Common Test may have either relative or absolute paths.</p></note>
<note><p>Arbitrary start flags to the Erlang Runtime System may also be passed as
- parameters to <c>run_test</c>. It is, for example, useful to be able to
+ parameters to <c>ct_run</c>. It is, for example, useful to be able to
pass directories that should be added to the Erlang code server search path
with the <c>-pa</c> or <c>-pz</c> flag. If you have common help- or library
modules for test suites (separately compiled), stored in other directories
than the test suite directories, these help/lib directories are preferrably
added to the code path this way. Example:</p>
- <p><c>$ run_test -dir ./chat_server -logdir ./chat_server/testlogs -pa $PWD/chat_server/ebin</c></p>
+ <p><c>$ ct_run -dir ./chat_server -logdir ./chat_server/testlogs -pa $PWD/chat_server/ebin</c></p>
<p>Note how in this example, the absolute path of the <c>chat_server/ebin</c>
directory is passed to the code server. This is essential since relative
paths are stored by the code server as relative, and Common Test changes
the current working directory of the Erlang Runtime System during the test run!</p>
</note>
- <p>For more information about the <c>run_test</c> program, see the
+ <p>For more information about the <c>ct_run</c> program, see the
<seealso marker="install_chapter#general">Installation</seealso> chapter.
</p>
</section>
@@ -188,7 +188,7 @@
<section>
<title>Running tests from the Web based GUI</title>
- <p>The web based GUI, VTS, is started with the <c>run_test</c>
+ <p>The web based GUI, VTS, is started with the <c>ct_run</c>
program. From the GUI you can load config files, and select
directories, suites and cases to run. You can also state the
config files, directories, suites and cases on the command line
@@ -196,22 +196,22 @@
</p>
<list>
- <item><c>run_test -vts</c></item>
- <item><c><![CDATA[run_test -vts -config <configfilename>]]></c></item>
- <item><c><![CDATA[run_test -vts -config <configfilename> -suite <suitewithfullpath>
+ <item><c>ct_run -vts</c></item>
+ <item><c><![CDATA[ct_run -vts -config <configfilename>]]></c></item>
+ <item><c><![CDATA[ct_run -vts -config <configfilename> -suite <suitewithfullpath>
-case <casename>]]></c></item>
</list>
<p>From the GUI you can run tests and view the result and the logs.
</p>
- <p>Note that <c>run_test -vts</c> will try to open the Common Test start
+ <p>Note that <c>ct_run -vts</c> will try to open the Common Test start
page in an existing web browser window or start the browser if it is
not running. Which browser should be started may be specified with
the browser start command option:</p>
- <p><c><![CDATA[run_test -vts -browser <browser_start_cmd>]]></c></p>
+ <p><c><![CDATA[ct_run -vts -browser <browser_start_cmd>]]></c></p>
<p>Example:</p>
- <p><c><![CDATA[$ run_test -vts -browser 'firefox&']]></c></p>
+ <p><c><![CDATA[$ ct_run -vts -browser 'firefox&']]></c></p>
<p>Note that the browser must run as a separate OS process or VTS will hang!</p>
<p>If no specific browser start command is specified, Firefox will
be the default browser on Unix platforms and Internet Explorer on Windows.
@@ -227,10 +227,10 @@
<p>Common Test provides an Erlang API for running tests. The main (and most
flexible) function for specifying and executing tests is called
<c>ct:run_test/1</c>. This function takes the same start parameters as
- the <c>run_test</c> program described above, only the flags are instead
+ the <c>ct_run</c> program described above, only the flags are instead
given as options in a list of key-value tuples. E.g. a test specified
- with <c>run_test</c> like:</p>
- <p><c>$ run_test -suite ./my_SUITE -logdir ./results</c></p>
+ with <c>ct_run</c> like:</p>
+ <p><c>$ ct_run -suite ./my_SUITE -logdir ./results</c></p>
<p>is with <c>ct:run_test/1</c> specified as:</p>
<p><c>1> ct:run_test([{suite,"./my_SUITE"},{logdir,"./results"}]).</c></p>
<p>For detailed documentation, please see the <c>ct</c> manual page.</p>
@@ -253,17 +253,17 @@
manually and call <c>ct:install/1</c> to install any configuration
data you might need (use <c>[]</c> as argument otherwise), then
call <c>ct:start_interactive/0</c> to start Common Test. If you use
- the <c>run_test</c> program, you may start the Erlang shell and Common Test
+ the <c>ct_run</c> program, you may start the Erlang shell and Common Test
in the same go by using the <c>-shell</c> and, optionally, the <c>-config</c>
and/or <c>-userconfig</c> flag. Examples:
</p>
<list>
- <item><c>run_test -shell</c></item>
- <item><c><![CDATA[run_test -shell -config cfg/db.cfg]]></c></item>
- <item><c><![CDATA[run_test -shell -userconfig db_login testuser x523qZ]]></c></item>
+ <item><c>ct_run -shell</c></item>
+ <item><c><![CDATA[ct_run -shell -config cfg/db.cfg]]></c></item>
+ <item><c><![CDATA[ct_run -shell -userconfig db_login testuser x523qZ]]></c></item>
</list>
- <p>If no config file is given with the <c>run_test</c> command,
+ <p>If no config file is given with the <c>ct_run</c> command,
a warning will be displayed. If Common Test has been run from the same
directory earlier, the same config file(s) will be used
again. If Common Test has not been run from this directory before, no
@@ -293,7 +293,7 @@
<c>ctlog.html</c> in the <c><![CDATA[ct_run.<timestamp>]]></c>
directory. A link to this file will be available in the file
named <c>last_interactive.html</c> in the directory from which
- you executed <c>run_test</c>. Currently, specifying a different
+ you executed <c>ct_run</c>. Currently, specifying a different
root directory for the logs than the current working directory,
is not supported.</p>
@@ -309,7 +309,7 @@
<section>
<title>Step by step execution of test cases with the Erlang Debugger</title>
- <p>By means of <c>run_test -step [opts]</c>, or by passing the
+ <p>By means of <c>ct_run -step [opts]</c>, or by passing the
<c>{step,Opts}</c> option to <c>ct:run_test/1</c>, it is possible
to get the Erlang Debugger started automatically and use its
graphical interface to investigate the state of the current test
@@ -345,12 +345,12 @@
for <c>ct</c>). There are two general types of terms:
configuration terms and test specification terms.</p>
<p>With configuration terms it is possible to e.g. label the test
- run (similar to <c>run_test -label</c>), evaluate arbitrary expressions
+ run (similar to <c>ct_run -label</c>), evaluate arbitrary expressions
before starting a test, import configuration
data (similar to
- <c>run_test -config/-userconfig</c>), specify HTML log directories (similar
+ <c>ct_run -config/-userconfig</c>), specify HTML log directories (similar
to
- <c>run_test -logdir</c>), give aliases to test nodes and test
+ <c>ct_run -logdir</c>), give aliases to test nodes and test
directories (to make a specification easier to read and
maintain), enable code coverage analysis (see
the <seealso marker="cover_chapter#cover">Code Coverage
@@ -359,7 +359,7 @@
Event Handling</seealso> chapter). There is also a term for
specifying include directories that should be passed on to the
compiler when automatic compilation is performed (similar
- to <c>run_test -include</c>, see above).</p>
+ to <c>ct_run -include</c>, see above).</p>
<p>With test specification terms it is possible to state exactly
which tests should run and in which order. A test term specifies
either one or more suites, one or more test case groups, or one
@@ -535,7 +535,7 @@
<p>It is possible for the user to provide a test specification that
includes (for Common Test) unrecognizable terms. If this is desired,
the <c>-allow_user_terms</c> flag should be used when starting tests with
- <c>run_test</c>. This forces Common Test to ignore unrecognizable terms.
+ <c>ct_run</c>. This forces Common Test to ignore unrecognizable terms.
Note that in this mode, Common Test is not able to check the specification
for errors as efficiently as if the scanner runs in default mode.
If <c>ct:run_test/1</c> is used for starting the tests, the relaxed scanner
@@ -661,11 +661,11 @@
</pre>
<p>To install the CSS file (Common Test inlines the definition in the
- HTML code), the name may be provided when executing <c>run_test</c>.
+ HTML code), the name may be provided when executing <c>ct_run</c>.
Example:</p>
<pre>
- $ run_test -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css
+ $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css
</pre>
<p>Categories in a CSS file installed with the <c>-stylesheet</c> flag
@@ -738,7 +738,7 @@
means of time, it is also possible to specify what action Common Test should
take upon timeout. Either Common Test performs all tests in the current run before stopping,
or it stops as soon as the current test job is finished. Repetition can be activated by
- means of <c>run_test</c> start flags, or tuples in the <c>ct:run:test/1</c>
+ means of <c>ct_run</c> start flags, or tuples in the <c>ct:run:test/1</c>
option list argument. The flags (options in parenthesis) are:</p>
<list>
<item><c>-repeat N ({repeat,N})</c>, where <c>N</c> is a positive integer.</item>
@@ -774,7 +774,7 @@
<p>Example 1:</p>
<pre>
- $ run_test -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -force_stop</pre>
+ $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -force_stop</pre>
<p>Here the suites in test directory to1, followed by the suites in to2, will be executed
in one test run. A timeout event will occur after 10 minutes. As long as there is time
left, Common Test will repeat the test run (i.e. starting over with the to1 test).
@@ -787,7 +787,7 @@
$ date
Fri Sep 28 15:00:00 MEST 2007
- $ run_test -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -until 160000</pre>
+ $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -until 160000</pre>
<p>Here the same test run as in the example above will be executed (and possibly repeated).
In this example, however, the timeout will occur after 1 hour and when that happens,
Common Test will finish the entire test run before stopping (i.e. the to1 and to2 test
@@ -795,7 +795,7 @@
<p>Example 3:</p>
<pre>
- $ run_test -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -repeat 5</pre>
+ $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -repeat 5</pre>
<p>Here the test run, including both the to1 and the to2 test, will be repeated 5 times.</p>
<note><p>This feature should not be confused with the <c>repeat</c> property of a test
@@ -814,7 +814,7 @@
of the <c>-silent_connections</c> flag:</p>
<pre>
- run_test -silent_connections [conn_types]
+ ct_run -silent_connections [conn_types]
</pre>
<p>where <c>conn_types</c> specifies <c>telnet, ftp, rpc</c> and/or <c>snmp</c>.</p>
@@ -822,11 +822,11 @@
<p>Example:</p>
<pre>
- run_test ... -silent_connections telnet ftp</pre>
+ ct_run ... -silent_connections telnet ftp</pre>
<p>switches off logging for telnet and ftp connections.</p>
<pre>
- run_test ... -silent_connections</pre>
+ ct_run ... -silent_connections</pre>
<p>switches off logging for all connection types.</p>
diff --git a/lib/common_test/doc/src/test_structure_chapter.xml b/lib/common_test/doc/src/test_structure_chapter.xml
index cd38ae0c7c..b9ca59135d 100644
--- a/lib/common_test/doc/src/test_structure_chapter.xml
+++ b/lib/common_test/doc/src/test_structure_chapter.xml
@@ -144,7 +144,7 @@
be used when the test suite needs to write to files.
</item>
- <tag><em>run_test</em></tag>
+ <tag><em>ct_run</em></tag>
<item>
The name of an executable program that may be
used as an interface for specifying and running
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 1dbf83ee10..405dc40c8b 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -97,7 +97,7 @@
%%% <code>install([{config,["config_node.ctc","config_user.ctc"]}])</code>.</p>
%%%
%%% <p>Note that this function is automatically run by the
-%%% <code>run_test</code> program.</p>
+%%% <code>ct_run</code> program.</p>
install(Opts) ->
ct_run:install(Opts).
@@ -179,10 +179,10 @@ run(TestDirs) ->
%%% Result = [TestResult] | {error,Reason}
%%% @doc Run tests as specified by the combination of options in <code>Opts</code>.
%%% The options are the same as those used with the
-%%% <seealso marker="run_test#run_test"><code>run_test</code></seealso> program.
+%%% <seealso marker="ct_run#ct_run"><code>ct_run</code></seealso> program.
%%% Note that here a <code>TestDir</code> can be used to point out the path to
%%% a <code>Suite</code>. Note also that the option <code>testcase</code>
-%%% corresponds to the <code>-case</code> option in the <code>run_test</code>
+%%% corresponds to the <code>-case</code> option in the <code>ct_run</code>
%%% program. Configuration files specified in <code>Opts</code> will be
%%% installed automatically at startup.
run_test(Opts) ->
@@ -225,7 +225,7 @@ step(TestDir,Suite,Case,Opts) ->
%%%
%%% <p>From this mode all test case support functions can be executed
%%% directly from the erlang shell. The interactive mode can also be
-%%% started from the OS command line with <code>run_test -shell
+%%% started from the OS command line with <code>ct_run -shell
%%% [-config File...]</code>.</p>
%%%
%%% <p>If any functions using "required config data" (e.g. telnet or
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 586b3893f1..d0e6ba5fa6 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -65,12 +65,12 @@
%%%-----------------------------------------------------------------
%%% @spec script_start() -> void()
%%%
-%%% @doc Start tests via the run_test program or script.
+%%% @doc Start tests via the ct_run program or script.
%%%
-%%% <p>Example:<br/><code>./run_test -config config.ctc -dir
+%%% <p>Example:<br/><code>./ct_run -config config.ctc -dir
%%% $TEST_DIR</code></p>
%%%
-%%% <p>Example:<br/><code>./run_test -config config.ctc -suite
+%%% <p>Example:<br/><code>./ct_run -config config.ctc -suite
%%% $SUITE_PATH/$SUITE_NAME [-case $CASE_NAME]</code></p>
%%%
script_start() ->
@@ -80,7 +80,7 @@ script_start() ->
(_) -> true end, Init),
%% convert relative dirs added with pa or pz (pre erl_args on
- %% the run_test command line) to absolute so that app modules
+ %% the ct_run command line) to absolute so that app modules
%% can be found even after CT changes CWD to logdir
rel_to_abs(CtArgs),
@@ -482,11 +482,11 @@ script_start4(Opts = #opts{tests = Tests}, Args) ->
%%%-----------------------------------------------------------------
%%% @spec script_usage() -> ok
-%%% @doc Print usage information for <code>run_test</code>.
+%%% @doc Print usage information for <code>ct_run</code>.
script_usage() ->
io:format("\n\nUsage:\n\n"),
io:format("Run tests in web based GUI:\n\n"
- "\trun_test -vts [-browser Browser]"
+ "\tct_run -vts [-browser Browser]"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
"\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
"\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
@@ -497,7 +497,7 @@ script_usage() ->
"\n\t[-scale_timetraps]"
"\n\t[-basic_html]\n\n"),
io:format("Run tests from command line:\n\n"
- "\trun_test [-dir TestDir1 TestDir2 .. TestDirN] |"
+ "\tct_run [-dir TestDir1 TestDir2 .. TestDirN] |"
"\n\t[-suite Suite1 Suite2 .. SuiteN [-case Case1 Case2 .. CaseN]]"
"\n\t[-step [config | keep_inactive]]"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
@@ -517,7 +517,7 @@ script_usage() ->
"\n\t[-duration HHMMSS [-force_stop]] |"
"\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
io:format("Run tests using test specification:\n\n"
- "\trun_test -spec TestSpec1 TestSpec2 .. TestSpecN"
+ "\tct_run -spec TestSpec1 TestSpec2 .. TestSpecN"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
"\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
"\n\t[-logdir LogDir]"
@@ -535,11 +535,11 @@ script_usage() ->
"\n\t[-duration HHMMSS [-force_stop]] |"
"\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
io:format("Refresh the HTML index files:\n\n"
- "\trun_test -refresh_logs [LogDir]"
+ "\tct_run -refresh_logs [LogDir]"
"[-logdir LogDir] "
"[-basic_html]\n\n"),
io:format("Run CT in interactive mode:\n\n"
- "\trun_test -shell"
+ "\tct_run -shell"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
"\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n").
@@ -2103,7 +2103,7 @@ get_pa_pz([], PA, PZ) ->
{PA,PZ}.
%% This function translates ct:run_test/1 start options
-%% to run_test start arguments (on the init arguments format) -
+%% to ct_run start arguments (on the init arguments format) -
%% this is useful mainly for testing the ct_run start functions.
opts2args(EnvStartOpts) ->
lists:flatmap(fun({config,CfgFiles}) ->
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index e1f24b602d..c3d65b4cb5 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -310,9 +310,9 @@
(there will not even be a warning if there is a mismatch).</p>
</item>
- <tag><c>{no_auto_import,[F/A, ...]}</c></tag>
+ <tag><c>{no_auto_import,[{F,A}, ...]}</c></tag>
<item>
- <p>Makes the function <c>F/A</c> no longer beeing
+ <p>Makes the function <c>F/A</c> no longer being
auto-imported from the module <c>erlang</c>, which resolves
BIF name clashes. This option has to be used to resolve name
clashes with BIFs auto-imported before R14A, if one wants to
@@ -323,8 +323,12 @@
without module prefix to local or imported functions before
trying auto-imported BIFs. If the BIF is to be
called, use the <c>erlang</c> module prefix in the call, not
- <c>{ no_auto_import,[F/A, ...]}</c></p>
+ <c>{ no_auto_import,[{F,A}, ...]}</c></p>
</note>
+ <p>If this option is written in the source code, as a
+ <c>-compile</c> directive, the syntax <c>F/A</c> can be used instead
+ of <c>{F,A}</c>. Example:</p>
+ <code>-compile({no_auto_import,[error/1]}).</code>
</item>
</taglist>
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl
index 19b006e750..1628ca69b1 100644
--- a/lib/debugger/test/int_eval_SUITE.erl
+++ b/lib/debugger/test/int_eval_SUITE.erl
@@ -65,10 +65,7 @@ bifs_outside_erlang(Config) when is_list(Config) ->
Self = self(),
ok = io:format("Self: ~p", [Self]),
Info = ets:info(Id),
- {owner,Self} = lists:nth(2, Info),
- %% Was
- %% {owner,Self} = element(2, Info),
- %% in R10B.
+ Self = proplists:get_value(owner, Info),
?IM:ets_delete(Id),
ok
end,
diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl
index 87a1401a02..4f5f035a65 100644
--- a/lib/docbuilder/src/docb_main.erl
+++ b/lib/docbuilder/src/docb_main.erl
@@ -34,14 +34,23 @@
%% Parses the source file File and transforms the result to html,
%% latex and/or man page format.
process(File, Opts) ->
-
- File1 = File ++ ".tmpconv",
- os:cmd("sed -e 's/xi:include[ \t]*href/include file/g' -e 's/xmlns:xi=\"http:\\/\\/www.w3.org\\/2001\\/XInclude\"//g' < " ++
- File ++ ".xml > " ++ File1 ++ ".xml"), %LATH
+
+ 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 ->
- file:delete(File1 ++ ".xml"),
+ delete_tmp_file(SrcType, File1),
errors;
{ok, Tree} ->
From = element(1, Tree),
@@ -62,15 +71,21 @@ process(File, Opts) ->
Result = [transform(From, To, Opts, File, Tree)||To <- Tos],
case lists:member(transformation_error,Result) of
true ->
- file:delete(File1 ++ ".xml"),
+ delete_tmp_file(SrcType, File1),
errors;
_ ->
- file:delete(File1 ++ ".xml"),
+ 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
diff --git a/lib/erl_docgen/Makefile b/lib/erl_docgen/Makefile
index c5bed632a5..93a6353cac 100644
--- a/lib/erl_docgen/Makefile
+++ b/lib/erl_docgen/Makefile
@@ -1,19 +1,20 @@
-# ``The contents of this file are subject to the Erlang Public License,
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-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 via the world wide web at http://www.erlang.org/.
+# 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 Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
+# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -22,9 +23,11 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = priv
+SUB_DIRECTORIES = src priv
#doc/src
+include vsn.mk
+VSN = $(ERL_DOCGEN_VSN)
SPECIAL_TARGETS =
diff --git a/lib/erl_docgen/ebin/.gitignore b/lib/erl_docgen/ebin/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_docgen/ebin/.gitignore
diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript
new file mode 100644
index 0000000000..840fed6dd5
--- /dev/null
+++ b/lib/erl_docgen/priv/bin/specs_gen.escript
@@ -0,0 +1,129 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+
+%%% <script> [-I<dir>]... [-o<dir>] [-module Module] [File]
+%%%
+%%% Use EDoc and the layout module 'otp_specs' to create an XML file
+%%% containing Dialyzer types and specifications (-type, -spec).
+%%%
+%%% Options:
+%%%
+%%% "-o<dir>" The output directory for the created file.
+%%% Default is ".".
+%%% "-I<dir>" Directory to be searched when including a file.
+%%% "-module Module"
+%%% Module name to use when there is no File argument.
+%%% A temporary file will be created.
+%%% Exactly one of -module Module and File must be given.
+%%%
+%%% The name of the generated file is "specs_<module>.xml". Its exact
+%%% format is not further described here.
+
+main(Args) ->
+ case catch parse(Args, [], ".", no_module) of
+ {ok, FileSpec, InclFs, Dir} ->
+ call_edoc(FileSpec, InclFs, Dir);
+ {error, Msg} ->
+ io:format("~s\n", [Msg]),
+ usage()
+ end.
+
+parse(["-o"++Dir | Opts], InclFs, _, Module) ->
+ parse(Opts, InclFs, Dir, Module);
+parse(["-I"++I | Opts], InclFs, Dir, Module) ->
+ parse(Opts, [I | InclFs], Dir, Module);
+parse(["-module", Module | Opts], InclFs, Dir, _) ->
+ parse(Opts, InclFs, Dir, Module);
+parse([File], InclFs, Dir, no_module) ->
+ {ok, {file, File}, lists:reverse(InclFs), Dir};
+parse([_], _, _, _) ->
+ {error, io_lib:format("Cannot have both -module option and file", [])};
+parse([], _, _, no_module) ->
+ {error, io_lib:format("Missing -module option or file", [])};
+parse([], InclFs, Dir, Module) ->
+ {ok, {module, Module}, lists:reverse(InclFs), Dir};
+parse(Args, _, _, _) ->
+ {error, io_lib:format("Bad arguments: ~p", [Args])}.
+
+usage() ->
+ io:format("usage: ~s [-I<include_dir>]... [-o<out_dir>] "
+ "[-module <module>] [file]\n", [escript:script_name()]),
+ halt(1).
+
+call_edoc(FileSpec, InclFs, Dir) ->
+ Incl = [{includes, InclFs}],
+ Pre = [{preprocess, true}],
+ Choice = [{dialyzer_specs, all}],
+ DirOpt = [{dir, Dir}],
+ Pretty = [{pretty_print, erl_pp}],
+ Layout = [{layout, otp_specs},
+ {file_suffix, ".specs"},
+ {stylesheet, ""}],
+ Warn = [{report_missing_type, false},
+ {report_type_mismatch, false}],
+ OptionList = (DirOpt ++ Choice ++ Pre ++ Warn ++ Pretty ++ Layout ++ Incl),
+ {File, TmpFile} = case FileSpec of
+ {file, File0} ->
+ {File0, false};
+ {module, Module} ->
+ {create_tmp_file(Dir, Module), true}
+ end,
+ try edoc:files([File], OptionList) of
+ ok ->
+ clean_up(Dir, File, TmpFile),
+ rename(Dir, File)
+ catch
+ _:_ ->
+ io:format("EDoc could not process file '~s'\n", [File]),
+ clean_up(Dir, File, TmpFile),
+ halt(3)
+ end.
+
+rename(Dir, F) ->
+ Mod = filename:basename(F, ".erl"),
+ Old = filename:join(Dir, Mod ++ ".specs"),
+ New = filename:join(Dir, "specs_" ++ Mod ++ ".xml"),
+ case file:rename(Old, New) of
+ ok ->
+ ok;
+ {error, R} ->
+ R1 = file:format_error(R),
+ io:format("could not rename file '~s': ~s\n", [New, R1]),
+ halt(2)
+ end.
+
+clean_up(Dir, File, TmpFile) ->
+ [file:delete(File) || TmpFile],
+ _ = [file:delete(filename:join(Dir, F)) ||
+ F <- ["packages-frame.html",
+ "overview-summary.html",
+ "modules-frame.html",
+ "index.html", "erlang.png", "edoc-info"]],
+ ok.
+
+create_tmp_file(Dir, Module) ->
+ TmpFile = filename:join(Dir, Module++".erl"),
+ case file:write_file(TmpFile, "-module(" ++ Module ++ ").\n") of
+ ok ->
+ TmpFile;
+ {error, R} ->
+ R1 = file:format_error(R),
+ io:format("could not write file '~s': ~s\n", [TmpFile, R1]),
+ halt(2)
+ end.
diff --git a/lib/erl_docgen/priv/bin/xref_mod_app.escript b/lib/erl_docgen/priv/bin/xref_mod_app.escript
new file mode 100755
index 0000000000..fcc3a96ada
--- /dev/null
+++ b/lib/erl_docgen/priv/bin/xref_mod_app.escript
@@ -0,0 +1,107 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+
+%%% Find all applications and all modules given a root directory.
+%%% Output an XML file that can be used for finding which application
+%%% a given module belongs to.
+%%%
+%%% Options:
+%%%
+%%% "-topdir <D>" Applications are found under D/lib/.
+%%% The default value is $ERL_TOP.
+%%%
+%%% "-outfile <F>" Output is written onto F.
+%%% The default value is "mod2app.xml".
+%%%
+%%% The output file has the following format:
+%%%
+%%% <?xml version="1.0"?>
+%%% <mod2app>
+%%% <module name="ModName1">AppName1</module>
+%%% ...
+%%% <mod2app>
+%%%
+%%% meaning that module ModName1 resides in application AppName1.
+
+main(Args) ->
+ case catch parse(Args, os:getenv("ERL_TOP"), "mod2app.xml") of
+ {ok, TopDir, OutFile} ->
+ case modapp(TopDir) of
+ [] ->
+ io:format("no applications found\n"),
+ halt(3);
+ MA ->
+ Layout = layout(MA),
+ XML = xmerl:export_simple(Layout, xmerl_xml),
+ write_file(XML, OutFile)
+ end;
+ {error, Msg} ->
+ io:format("~s\n", [Msg]),
+ usage()
+ end.
+
+parse(["-topdir", TopDir | Opts], _, OutFile) ->
+ parse(Opts, TopDir, OutFile);
+parse(["-outfile", OutFile | Opts], TopDir, _) ->
+ parse(Opts, TopDir, OutFile);
+parse([], TopDir, OutFile) ->
+ {ok, TopDir, OutFile};
+parse([Opt | _], _, _) ->
+ {error, io_lib:format("Bad option: ~p", [Opt])}.
+
+usage() ->
+ io:format("usage: ~s [-topdir <dir>] [-outfile <file>]\n",
+ [escript:script_name()]),
+ halt(1).
+
+modapp(TopDir) ->
+ AppDirs = filelib:wildcard(filename:join([TopDir,"lib","*"])),
+ AM = [appmods(D) || D <- AppDirs],
+ lists:keysort(1, [{M,A} || {A,Ms} <- AM, M <- Ms]).
+
+%% It's OK if too much data is generated as long as all applications
+%% and all modules are mentioned.
+appmods(D) ->
+ ErlFiles = filelib:wildcard(filename:join([D,"src","*.erl"])),
+ AppV = filename:basename(D),
+ App = case string:rstr(AppV, "-") of
+ 0 -> AppV;
+ P -> string:sub_string(AppV, 1, P-1)
+ end,
+ {App, [filename:basename(EF, ".erl") || EF <- ErlFiles]}.
+
+-include_lib("xmerl/include/xmerl.hrl").
+
+-define(IND(N), lists:duplicate(N, $\s)).
+-define(NL, "\n").
+
+layout(MAL) ->
+ ML = lists:append([[?IND(2),{module,[{name,M}],[A]},?NL] || {M,A} <- MAL]),
+ [?NL,{mod2app,[?NL|ML]},?NL].
+
+write_file(Text, File) ->
+ case file:open(File, [write]) of
+ {ok, FD} ->
+ io:put_chars(FD, Text),
+ ok = file:close(FD);
+ {error, R} ->
+ R1 = file:format_error(R),
+ io:format("could not write file '~s': ~s\n", [File, R1]),
+ halt(2)
+ end.
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd
index 7b9974fbda..c1237766e1 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd
+++ b/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd
@@ -26,15 +26,18 @@
<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
<!ELEMENT funcs (func)+ >
-<!ELEMENT func (name+,fsummary,type?,desc?) >
+<!ELEMENT func (name+,type_desc+,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 desc (%block;|quote|br|marker|warning|note|anno)* >
<!ELEMENT authors (aname,email)+ >
<!ELEMENT aname (#PCDATA) >
<!ELEMENT email (#PCDATA) >
<!ELEMENT section (marker*,title,(%block;|quote|br|marker|
warning|note)*) >
+<!ELEMENT datatypes (datatype)+ >
+<!ELEMENT datatype (name+,desc?) >
+<!ELEMENT type_desc (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd
index 21656a1446..9905086ff4 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd
+++ b/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd
@@ -22,7 +22,7 @@
%common.refs;
<!ELEMENT erlref (header,module,modulesummary,description,
- (section|funcs)*,authors?) >
+ (section|funcs|datatypes)*,authors?) >
<!ELEMENT module (#PCDATA) >
<!ELEMENT modulesummary (#PCDATA) >
diff --git a/lib/erl_docgen/priv/dtd_man_entities/xhtml-lat1.ent b/lib/erl_docgen/priv/dtd_man_entities/xhtml-lat1.ent
index 3df9970a43..7a07e2c406 100644
--- a/lib/erl_docgen/priv/dtd_man_entities/xhtml-lat1.ent
+++ b/lib/erl_docgen/priv/dtd_man_entities/xhtml-lat1.ent
@@ -21,26 +21,26 @@
<!ENTITY sect "&#167;"> <!-- section sign, U+00A7 ISOnum -->
<!ENTITY uml "&#168;"> <!-- diaeresis = spacing diaeresis,
U+00A8 ISOdia -->
-<!ENTITY copy "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
+<!ENTITY copy "(C)"> <!-- copyright sign, U+00A9 ISOnum -->
<!ENTITY ordf "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
-<!ENTITY laquo "&#171;"> <!-- left-pointing double angle quotation mark
- = left pointing guillemet, U+00AB ISOnum -->
+<!ENTITY laquo "&#34;"> <!-- left-pointing double angle quotation mark
+ = left pointing guillemetn = " in man pages, U+00AB ISOnum -->
<!ENTITY not "&#172;"> <!-- not sign = discretionary hyphen,
U+00AC ISOnum -->
-<!ENTITY shy "&#173;"> <!-- soft hyphen = discretionary hyphen,
+<!ENTITY shy ""> <!-- soft hyphen = discretionary hyphen,
U+00AD ISOnum -->
-<!ENTITY reg "&#174;"> <!-- registered sign = registered trade mark sign,
+<!ENTITY reg "(R)"> <!-- registered sign = registered trade mark sign,
U+00AE ISOnum -->
<!ENTITY macr "&#175;"> <!-- macron = spacing macron = overline
= APL overbar, U+00AF ISOdia -->
<!ENTITY deg "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
-<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign,
+<!ENTITY plusmn "+/-"> <!-- plus-minus sign = plus-or-minus sign,
U+00B1 ISOnum -->
<!ENTITY sup2 "&#178;"> <!-- superscript two = superscript digit two
= squared, U+00B2 ISOnum -->
<!ENTITY sup3 "&#179;"> <!-- superscript three = superscript digit three
= cubed, U+00B3 ISOnum -->
-<!ENTITY acute "&#180;"> <!-- acute accent = spacing acute,
+<!ENTITY acute "'"> <!-- acute accent = spacing acute,
U+00B4 ISOdia -->
<!ENTITY micro "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
<!ENTITY para "&#182;"> <!-- pilcrow sign = paragraph sign,
@@ -62,134 +62,134 @@
= fraction three quarters, U+00BE ISOnum -->
<!ENTITY iquest "&#191;"> <!-- inverted question mark
= turned question mark, U+00BF ISOnum -->
-<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave
+<!ENTITY Agrave "A"> <!-- latin capital letter A with grave
= latin capital letter A grave,
U+00C0 ISOlat1 -->
-<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute,
+<!ENTITY Aacute "A"> <!-- latin capital letter A with acute,
U+00C1 ISOlat1 -->
-<!ENTITY Acirc "&#194;"> <!-- latin capital letter A with circumflex,
+<!ENTITY Acirc "A"> <!-- latin capital letter A with circumflex,
U+00C2 ISOlat1 -->
-<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde,
+<!ENTITY Atilde "A"> <!-- latin capital letter A with tilde,
U+00C3 ISOlat1 -->
-<!ENTITY Auml "&#196;"> <!-- latin capital letter A with diaeresis,
+<!ENTITY Auml "A"> <!-- latin capital letter A with diaeresis,
U+00C4 ISOlat1 -->
-<!ENTITY Aring "&#197;"> <!-- latin capital letter A with ring above
+<!ENTITY Aring "A"> <!-- latin capital letter A with ring above
= latin capital letter A ring,
U+00C5 ISOlat1 -->
-<!ENTITY AElig "&#198;"> <!-- latin capital letter AE
+<!ENTITY AElig "AE"> <!-- latin capital letter AE
= latin capital ligature AE,
U+00C6 ISOlat1 -->
-<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla,
+<!ENTITY Ccedil "C"> <!-- latin capital letter C with cedilla,
U+00C7 ISOlat1 -->
-<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave,
+<!ENTITY Egrave "E"> <!-- latin capital letter E with grave,
U+00C8 ISOlat1 -->
-<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute,
+<!ENTITY Eacute "E"> <!-- latin capital letter E with acute,
U+00C9 ISOlat1 -->
-<!ENTITY Ecirc "&#202;"> <!-- latin capital letter E with circumflex,
+<!ENTITY Ecirc "E"> <!-- latin capital letter E with circumflex,
U+00CA ISOlat1 -->
-<!ENTITY Euml "&#203;"> <!-- latin capital letter E with diaeresis,
+<!ENTITY Euml "E"> <!-- latin capital letter E with diaeresis,
U+00CB ISOlat1 -->
-<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave,
+<!ENTITY Igrave "I"> <!-- latin capital letter I with grave,
U+00CC ISOlat1 -->
-<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute,
+<!ENTITY Iacute "I"> <!-- latin capital letter I with acute,
U+00CD ISOlat1 -->
-<!ENTITY Icirc "&#206;"> <!-- latin capital letter I with circumflex,
+<!ENTITY Icirc "I"> <!-- latin capital letter I with circumflex,
U+00CE ISOlat1 -->
-<!ENTITY Iuml "&#207;"> <!-- latin capital letter I with diaeresis,
+<!ENTITY Iuml "I"> <!-- latin capital letter I with diaeresis,
U+00CF ISOlat1 -->
<!ENTITY ETH "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
-<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde,
+<!ENTITY Ntilde "N"> <!-- latin capital letter N with tilde,
U+00D1 ISOlat1 -->
-<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave,
+<!ENTITY Ograve "O"> <!-- latin capital letter O with grave,
U+00D2 ISOlat1 -->
-<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute,
+<!ENTITY Oacute "O"> <!-- latin capital letter O with acute,
U+00D3 ISOlat1 -->
-<!ENTITY Ocirc "&#212;"> <!-- latin capital letter O with circumflex,
+<!ENTITY Ocirc "O"> <!-- latin capital letter O with circumflex,
U+00D4 ISOlat1 -->
-<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde,
+<!ENTITY Otilde "O"> <!-- latin capital letter O with tilde,
U+00D5 ISOlat1 -->
-<!ENTITY Ouml "&#214;"> <!-- latin capital letter O with diaeresis,
+<!ENTITY Ouml "O"> <!-- latin capital letter O with diaeresis,
U+00D6 ISOlat1 -->
-<!ENTITY times "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
+<!ENTITY times "x"> <!-- multiplication sign, U+00D7 ISOnum -->
<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke
= latin capital letter O slash,
U+00D8 ISOlat1 -->
-<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave,
+<!ENTITY Ugrave "U"> <!-- latin capital letter U with grave,
U+00D9 ISOlat1 -->
-<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute,
+<!ENTITY Uacute "U"> <!-- latin capital letter U with acute,
U+00DA ISOlat1 -->
-<!ENTITY Ucirc "&#219;"> <!-- latin capital letter U with circumflex,
+<!ENTITY Ucirc "U"> <!-- latin capital letter U with circumflex,
U+00DB ISOlat1 -->
-<!ENTITY Uuml "&#220;"> <!-- latin capital letter U with diaeresis,
+<!ENTITY Uuml "U"> <!-- latin capital letter U with diaeresis,
U+00DC ISOlat1 -->
-<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute,
+<!ENTITY Yacute "Y"> <!-- latin capital letter Y with acute,
U+00DD ISOlat1 -->
<!ENTITY THORN "&#222;"> <!-- latin capital letter THORN,
U+00DE ISOlat1 -->
<!ENTITY szlig "&#223;"> <!-- latin small letter sharp s = ess-zed,
U+00DF ISOlat1 -->
-<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave
+<!ENTITY agrave "a"> <!-- latin small letter a with grave
= latin small letter a grave,
U+00E0 ISOlat1 -->
-<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute,
+<!ENTITY aacute "a"> <!-- latin small letter a with acute,
U+00E1 ISOlat1 -->
-<!ENTITY acirc "&#226;"> <!-- latin small letter a with circumflex,
+<!ENTITY acirc "a"> <!-- latin small letter a with circumflex,
U+00E2 ISOlat1 -->
-<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde,
+<!ENTITY atilde "a"> <!-- latin small letter a with tilde,
U+00E3 ISOlat1 -->
-<!ENTITY auml "&#228;"> <!-- latin small letter a with diaeresis,
+<!ENTITY auml "a"> <!-- latin small letter a with diaeresis,
U+00E4 ISOlat1 -->
-<!ENTITY aring "&#229;"> <!-- latin small letter a with ring above
+<!ENTITY aring "a"> <!-- latin small letter a with ring above
= latin small letter a ring,
U+00E5 ISOlat1 -->
-<!ENTITY aelig "&#230;"> <!-- latin small letter ae
+<!ENTITY aelig "ae"> <!-- latin small letter ae
= latin small ligature ae, U+00E6 ISOlat1 -->
-<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla,
+<!ENTITY ccedil "c"> <!-- latin small letter c with cedilla,
U+00E7 ISOlat1 -->
-<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave,
+<!ENTITY egrave "e"> <!-- latin small letter e with grave,
U+00E8 ISOlat1 -->
-<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute,
+<!ENTITY eacute "e"> <!-- latin small letter e with acute,
U+00E9 ISOlat1 -->
-<!ENTITY ecirc "&#234;"> <!-- latin small letter e with circumflex,
+<!ENTITY ecirc "e"> <!-- latin small letter e with circumflex,
U+00EA ISOlat1 -->
-<!ENTITY euml "&#235;"> <!-- latin small letter e with diaeresis,
+<!ENTITY euml "e"> <!-- latin small letter e with diaeresis,
U+00EB ISOlat1 -->
-<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave,
+<!ENTITY igrave "i"> <!-- latin small letter i with grave,
U+00EC ISOlat1 -->
-<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute,
+<!ENTITY iacute "i"> <!-- latin small letter i with acute,
U+00ED ISOlat1 -->
-<!ENTITY icirc "&#238;"> <!-- latin small letter i with circumflex,
+<!ENTITY icirc "i"> <!-- latin small letter i with circumflex,
U+00EE ISOlat1 -->
-<!ENTITY iuml "&#239;"> <!-- latin small letter i with diaeresis,
+<!ENTITY iuml "i"> <!-- latin small letter i with diaeresis,
U+00EF ISOlat1 -->
<!ENTITY eth "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
-<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde,
+<!ENTITY ntilde "n"> <!-- latin small letter n with tilde,
U+00F1 ISOlat1 -->
-<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave,
+<!ENTITY ograve "o"> <!-- latin small letter o with grave,
U+00F2 ISOlat1 -->
-<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute,
+<!ENTITY oacute "o"> <!-- latin small letter o with acute,
U+00F3 ISOlat1 -->
-<!ENTITY ocirc "&#244;"> <!-- latin small letter o with circumflex,
+<!ENTITY ocirc "o"> <!-- latin small letter o with circumflex,
U+00F4 ISOlat1 -->
-<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde,
+<!ENTITY otilde "o"> <!-- latin small letter o with tilde,
U+00F5 ISOlat1 -->
-<!ENTITY ouml "&#246;"> <!-- latin small letter o with diaeresis,
+<!ENTITY ouml "o"> <!-- latin small letter o with diaeresis,
U+00F6 ISOlat1 -->
<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
-<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke,
+<!ENTITY oslash "o"> <!-- latin small letter o with stroke,
= latin small letter o slash,
U+00F8 ISOlat1 -->
-<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave,
+<!ENTITY ugrave "u"> <!-- latin small letter u with grave,
U+00F9 ISOlat1 -->
-<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute,
+<!ENTITY uacute "u"> <!-- latin small letter u with acute,
U+00FA ISOlat1 -->
-<!ENTITY ucirc "&#251;"> <!-- latin small letter u with circumflex,
+<!ENTITY ucirc "u"> <!-- latin small letter u with circumflex,
U+00FB ISOlat1 -->
-<!ENTITY uuml "&#252;"> <!-- latin small letter u with diaeresis,
+<!ENTITY uuml "u"> <!-- latin small letter u with diaeresis,
U+00FC ISOlat1 -->
-<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute,
+<!ENTITY yacute "y"> <!-- latin small letter y with acute,
U+00FD ISOlat1 -->
<!ENTITY thorn "&#254;"> <!-- latin small letter thorn with,
U+00FE ISOlat1 -->
-<!ENTITY yuml "&#255;"> <!-- latin small letter y with diaeresis,
+<!ENTITY yuml "y"> <!-- latin small letter y with diaeresis,
U+00FF ISOlat1 -->
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index bba0f97645..732560e303 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
+<!--
#
# %CopyrightBegin%
#
@@ -17,15 +17,315 @@
# under the License.
#
# %CopyrightEnd%
-
+
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
+ xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<xsl:include href="db_html_params.xsl"/>
+ <!-- Start of Dialyzer type/spec tags.
+ See also the template matching "name" and the template "menu.funcs"
+ -->
+
+ <xsl:param name="specs_file" select="''"/>
+ <xsl:variable name="i" select="document($specs_file)"></xsl:variable>
+
+ <xsl:param name="mod2app_file" select="''"/>
+ <xsl:variable name="m2a" select="document($mod2app_file)"></xsl:variable>
+ <xsl:key name="mod2app" match="module" use="@name"/>
+
+ <xsl:template name="err">
+ <xsl:param name="m"/>
+ <xsl:param name="n"/>
+ <xsl:param name="a"/>
+ <xsl:param name="s"/>
+ <xsl:message terminate="yes">
+ Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of
+ select="$n"/>/<xsl:value-of
+ select="$a"/>: <xsl:value-of select="$s"/>
+ </xsl:message>
+ </xsl:template>
+
+ <xsl:template name="spec_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="clause" select="@clause"/>
+ <xsl:variable name="spec0" select=
+ "$i/specs/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec" select="$spec0[string-length($clause) = 0
+ or position() = $clause]"/>
+ <xsl:if test="count($spec) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown spec</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:variable name="arity_clause">
+ <xsl:choose>
+ <xsl:when test="string-length(@clause) > 0">
+ <xsl:value-of select="@arity"/>/<xsl:value-of select="@clause"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@arity"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:message terminate="yes">
+ Error: did not expect a 'name' tag with name/arity attributes here!
+ </xsl:message>
+ </xsl:when>
+ <xsl:when test="ancestor::erlref">
+ <a name="{$name}-{$arity_clause}"></a>
+ <xsl:choose>
+ <xsl:when test="string(@with_guards) = 'no'">
+ <xsl:apply-templates select="$spec/contract/clause/head"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="contract">
+ <xsl:with-param name="contract" select="$spec/contract"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="contract">
+ <xsl:param name="contract"/>
+ <xsl:call-template name="clause">
+ <xsl:with-param name="clause" select="$contract/clause"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="clause">
+ <xsl:param name="clause"/>
+ <xsl:variable name="type_desc" select="../type_desc"/>
+ <xsl:for-each select="$clause">
+ <xsl:apply-templates select="head"/>
+ <xsl:if test="count(guard) > 0">
+ <xsl:call-template name="guard">
+ <xsl:with-param name="guard" select="guard"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="head">
+ <span class="bold_code">
+ <xsl:apply-templates/>
+ </span>
+ <br/>
+ </xsl:template>
+
+ <xsl:template name="guard">
+ <xsl:param name="guard"/>
+ <xsl:param name="type_desc"/>
+ <div class="REFBODY"><p>Types:</p>
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="subtype">
+ <xsl:param name="subtype"/>
+ <xsl:param name="type_desc"/>
+ <xsl:for-each select="$subtype">
+ <xsl:variable name="tname" select="typename"/>
+ <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/>
+ <div class="REFTYPES">
+ <span class="bold_code">
+ <xsl:apply-templates select="string"/>
+ </span>
+ </div>
+ <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- Note: <type_desc> has not been implemented for data types. -->
+
+ <!-- Similar to <d> -->
+ <xsl:template match="type_desc">
+ <div class="REFBODY">
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <!-- This is for debugging. All modules! -->
+ <xsl:template match="all_etypes">
+ <xsl:for-each select= "$i//type">
+ <pre>
+ <span class="bold_code">
+ <xsl:apply-templates select="typedecl"/>
+ </span><xsl:text>
+</xsl:text>
+ </pre>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- Datatypes -->
+ <xsl:template match="datatypes">
+ <h3>
+ <xsl:text>DATA TYPES</xsl:text>
+ </h3>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Datatype -->
+ <xsl:template match="datatype">
+ <p><xsl:apply-templates select="name"/></p>
+ <xsl:apply-templates select="desc"/>
+ </xsl:template>
+
+ <xsl:template match="typehead">
+ <span class="bold_code">
+ <xsl:apply-templates/>
+ </span><br/>
+ </xsl:template>
+
+ <!-- local_defs -->
+ <xsl:template match="local_defs">
+ <div class="REFBODY">
+ <xsl:apply-templates>
+ </xsl:apply-templates>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="local_def">
+ <div class="REFTYPES">
+ <span class="bold_code">
+ <xsl:apply-templates/>
+ </span>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="type_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length(@n_vars) > 0">
+ <xsl:value-of select="@n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="string-length($name) > 0">
+ <xsl:variable name="type" select=
+ "$i/specs/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]"/>
+
+ <xsl:if test="count($type) != 1">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n_vars"/>
+ <xsl:with-param name="s">unknown type</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="bold_code">
+ <xsl:value-of select="."/>
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Used both in <datatype> and in <func>! -->
+ <xsl:template match="anno">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="anno" select="normalize-space(text())"/>
+ <xsl:variable name="namespec"
+ select="ancestor::desc/preceding-sibling::name"/>
+ <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>)
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:variable name="mod" select="$namespec/@mod"/>
+ <xsl:variable name="name" select="$namespec/@name"/>
+ <xsl:variable name="arity" select="$namespec/@arity"/>
+ <xsl:variable name="clause" select="$namespec/@clause"/>
+ <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length($tmp_n_vars) > 0">
+ <xsl:value-of select="$tmp_n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0" select=
+ "$i/specs/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec_annos" select=
+ "$spec0[string-length($clause) = 0
+ or position() = $clause]/anno[.=$anno]"/>
+ <xsl:variable name="type_annos" select=
+ "$i/specs/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/>
+
+ <xsl:if test="count($spec_annos) = 0
+ and count($type_annos) = 0
+ and string-length($specs_file) > 0">
+ <xsl:variable name="n">
+ <xsl:choose>
+ <xsl:when test="string-length($arity) = 0">
+ <xsl:value-of select="$n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$arity"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n"/>
+ <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:value-of select="$anno"/>
+ </xsl:template>
+
+ <!-- Used for indentation of formatted types and specs -->
+ <xsl:template match="nbsp">
+ <xsl:text>&#160;</xsl:text>
+ </xsl:template>
+
+ <!-- End of Dialyzer type/spec tags -->
+
<!-- Page layout -->
<xsl:template name="pagelayout">
<xsl:param name="chapnum"/>
@@ -36,19 +336,19 @@
<title>Erlang -- <xsl:value-of select="header/title"/></title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
-
+
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
<script language="JavaScript" type="text/javascript">
<xsl:text disable-output-escaping="yes"><![CDATA[
- <!--
+ <!--
function getWinHeight() {
var myHeight = 0;
if( typeof( window.innerHeight ) == 'number' ) {
//Non-IE
myHeight = window.innerHeight;
- } else if( document.documentElement && ( document.documentElement.clientWidth ||
+ } else if( document.documentElement && ( document.documentElement.clientWidth ||
document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myHeight = document.documentElement.clientHeight;
@@ -56,7 +356,7 @@
//IE 4 compatible
myHeight = document.body.clientHeight;
}
- return myHeight;
+ return myHeight;
}
function setscrollpos() {
@@ -64,16 +364,16 @@
document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
}
- function addEvent(obj, evType, fn){
- if (obj.addEventListener){
- obj.addEventListener(evType, fn, true);
- return true;
- } else if (obj.attachEvent){
- var r = obj.attachEvent("on"+evType, fn);
- return r;
- } else {
- return false;
- }
+ function addEvent(obj, evType, fn){
+ if (obj.addEventListener){
+ obj.addEventListener(evType, fn, true);
+ return true;
+ } else if (obj.attachEvent){
+ var r = obj.attachEvent("on"+evType, fn);
+ return r;
+ } else {
+ return false;
+ }
}
addEvent(window, 'load', setscrollpos);
@@ -85,7 +385,7 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="curModule" select="$curModule"/>
</xsl:call-template>
-
+
<div id="content">
<div class="innertube">
@@ -124,17 +424,17 @@
<xsl:if test="$lname = 'releasenotes'">
<!-- .../part -->
<xsl:call-template name="releasenotes.content" />
- </xsl:if>
+ </xsl:if>
<xsl:if test="$lname = 'part'">
<!-- .../part -->
<xsl:call-template name="part.content" />
- </xsl:if>
+ </xsl:if>
<xsl:if test="$lname = 'chapter'">
<!-- .../part/chapter -->
<xsl:call-template name="chapter.content">
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
- </xsl:if>
+ </xsl:if>
<xsl:if test="$lname = 'application'">
<!-- .../application -->
<xsl:call-template name="app.content" />
@@ -178,37 +478,37 @@
<small>
<xsl:if test="boolean(/book/parts/part)">
<a href="users_guide.html">User's Guide</a><br/>
- </xsl:if>
+ </xsl:if>
<xsl:if test="boolean(/book/applications)">
<a href="index.html">Reference Manual</a><br/>
- </xsl:if>
+ </xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
<a href="release_notes.html">Release Notes</a><br/>
- </xsl:if>
+ </xsl:if>
<a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a><br/>
<a href="{$topdocdir}/index.html">Top</a>
</small>
</xsl:template>
-
+
<xsl:template name="menu_middle">
<!-- small>
<xsl:choose>
<xsl:when test="ancestor::parts">
<a href="users_guide_bibliography.html">Bibliography</a><br/>
<a href="users_guide_glossary.html">Glossary</a><br/>
- </xsl:when>
- <xsl:when test="ancestor::applications">
+ </xsl:when>
+ <xsl:when test="ancestor::applications">
<a href="ref_man_bibliography.html">Bibliography</a><br/>
<a href="ref_man_glossary.html">Glossary</a><br/>
- </xsl:when>
+ </xsl:when>
</xsl:choose>
</small -->
<br/>
<a href="javascript:openAllFlips()">Expand All</a><br/>
<a href="javascript:closeAllFlips()">Contract All</a>
- </xsl:template>
-
+ </xsl:template>
+
<!-- Book -->
<xsl:template match="/book">
@@ -243,7 +543,7 @@
<!-- Chapter/Section -->
<xsl:template match="chapter/section">
- <xsl:param name="chapnum"/>
+ <xsl:param name="chapnum"/>
<h3>
<a name="{generate-id(title)}">
<xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
@@ -302,7 +602,7 @@
<!-- Lists -->
-
+
<xsl:template match="list">
<xsl:param name="chapnum"/>
<ul>
@@ -330,7 +630,7 @@
</xsl:apply-templates>
</dl>
</xsl:template>
-
+
<xsl:template match="taglist/tag">
<xsl:param name="chapnum"/>
<dt>
@@ -377,7 +677,7 @@
</xsl:apply-templates>
</p>
</div>
- </div>
+ </div>
</xsl:template>
<!-- Paragraph -->
@@ -402,7 +702,7 @@
</xsl:template>
<xsl:template match="em">
- <strong><xsl:apply-templates/></strong>
+ <strong><xsl:apply-templates/></strong>
</xsl:template>
<!-- Code -->
@@ -507,7 +807,7 @@
<!-- Part -->
<xsl:template match="part">
<!-- Generate Glossary for Users Guide -->
- <!--xsl:call-template name="glossary">
+ <!--xsl:call-template name="glossary">
<xsl:with-param name="type">users_guide</xsl:with-param>
</xsl:call-template-->
@@ -530,9 +830,9 @@
<center><h4>Version <xsl:value-of select="$appver"/></h4></center>
<center><h4><xsl:value-of select="$gendate"/></h4></center>
-
+
<xsl:apply-templates select="chapter"/>
-
+
</xsl:template>
<!-- Menu.ug -->
@@ -565,10 +865,10 @@
</xsl:call-template>
</ul>
</div>
- </div>
+ </div>
</xsl:template>
-
-
+
+
<xsl:template name="menu.chapter">
<xsl:param name="entries"/>
<xsl:param name="chapnum"/>
@@ -596,7 +896,7 @@
<a href="{$chapter_file}.html">
Top of chapter
</a>
- </li>
+ </li>
<xsl:call-template name="menu.section">
<xsl:with-param name="entries"
select="section[title]"/>
@@ -623,7 +923,7 @@
<!-- Chapter (if top tag)-->
<xsl:template match="/chapter">
- <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes"
+ <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN">
<xsl:call-template name="pagelayout">
@@ -635,7 +935,7 @@
<!-- Chapter -->
<xsl:template match="chapter">
- <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes"
+ <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN">
<xsl:call-template name="pagelayout">
@@ -670,7 +970,7 @@
<xsl:template match="application">
<!-- Generate Glossary for Ref. Manual -->
- <!--xsl:call-template name="glossary">
+ <!--xsl:call-template name="glossary">
<xsl:with-param name="type">ref_man</xsl:with-param>
</xsl:call-template-->
@@ -678,7 +978,7 @@
<!--xsl:call-template name="bibliography">
<xsl:with-param name="type">ref_man</xsl:with-param>
</xsl:call-template-->
-
+
<xsl:document href="{$outdir}/index.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN">
@@ -695,9 +995,9 @@
<center><h4>Version <xsl:value-of select="$appver"/></h4></center>
<center><h4><xsl:value-of select="$gendate"/></h4></center>
-
+
<xsl:apply-templates select="erlref|cref|comref|fileref|appref"/>
-
+
</xsl:template>
<!-- Menu.ref -->
@@ -730,16 +1030,16 @@
</xsl:call-template>
</ul>
</div>
- </div>
+ </div>
</xsl:template>
-
-
+
+
<xsl:template name="menu.ref2">
<xsl:param name="entries"/>
<!--xsl:param name="genFuncMenu"/-->
<xsl:param name="curModule"/>
<xsl:for-each select="$entries">
-
+
<xsl:variable name="cval">
<xsl:choose>
<xsl:when test="local-name() = 'erlref'">
@@ -767,9 +1067,9 @@
<xsl:when test="local-name() = 'fileref'">false</xsl:when>
<xsl:when test="descendant::funcs">true</xsl:when>
<xsl:otherwise>false</xsl:otherwise>
- </xsl:choose>
+ </xsl:choose>
</xsl:variable>
-
+
<xsl:variable name="expanded">
<xsl:choose>
<xsl:when test="$curModule = $cval">true</xsl:when>
@@ -796,7 +1096,7 @@
<a href="{$link_cval}.html">
Top of manual page
</a>
- </li>
+ </li>
<xsl:call-template name="menu.funcs">
<xsl:with-param name="entries"
select="funcs/func/name"/>
@@ -823,7 +1123,7 @@
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
- </xsl:choose>
+ </xsl:choose>
</xsl:for-each>
</xsl:template>
@@ -831,7 +1131,7 @@
<xsl:template name="menu.funcs">
<xsl:param name="entries"/>
<xsl:param name="basename"/>
-
+
<xsl:for-each select="$entries">
<xsl:choose>
@@ -840,74 +1140,97 @@
<xsl:choose>
<xsl:when test="string-length($fname) > 0">
<li title="{$fname}">
- <a href="{$basename}.html#{$fname}">
+ <a href="{$basename}.html#{$fname}">
<xsl:value-of select="$fname"/>()
</a>
- </li>
+ </li>
</xsl:when>
<xsl:otherwise>
<li title="{name/nametext}">
- <a href="{$basename}.html#{name/nametext}">
+ <a href="{$basename}.html#{name/nametext}">
<xsl:value-of select="nametext"/>()
- </a>
- </li>
+ </a>
+ </li>
</xsl:otherwise>
- </xsl:choose>
+ </xsl:choose>
</xsl:when>
-
+
<xsl:when test="ancestor::erlref">
-
+
<xsl:variable name="tmpstring">
<xsl:value-of select="substring-before(substring-after(., '('), '->')"/>
- </xsl:variable>
-
+ </xsl:variable>
+
<xsl:variable name="ustring">
<xsl:choose>
<xsl:when test="string-length($tmpstring) > 0">
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="$tmpstring"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="substring-after(., '(')"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:otherwise>
</xsl:choose>
- </xsl:variable>
-
+ </xsl:variable>
+
<xsl:variable name="arity">
- <xsl:call-template name="calc-arity">
- <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
- <xsl:with-param name="no-of-pars" select="0"/>
- </xsl:call-template>
- </xsl:variable>
-
+ <xsl:choose>
+ <xsl:when test="string-length(@arity) > 0">
+ <!-- Dialyzer spec -->
+ <xsl:choose>
+ <xsl:when test="string-length(@clause) > 0">
+ <xsl:value-of select="@arity"/>/<xsl:value-of select="@clause"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@arity"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="calc-arity">
+ <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
+ <xsl:with-param name="no-of-pars" select="0"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
<xsl:variable name="fname">
- <xsl:variable name="fname1">
- <xsl:value-of select="substring-before(., '(')"/>
- </xsl:variable>
- <xsl:variable name="fname2">
- <xsl:value-of select="substring-after($fname1, 'erlang:')"/>
- </xsl:variable>
<xsl:choose>
- <xsl:when test="string-length($fname2) > 0">
- <xsl:value-of select="$fname2"/>
+ <xsl:when test="string-length(@name) > 0">
+ <!-- Dialyzer spec -->
+ <xsl:value-of select="@name"/>
</xsl:when>
<xsl:otherwise>
- <xsl:value-of select="$fname1"/>
+ <xsl:variable name="fname1">
+ <xsl:value-of select="substring-before(., '(')"/>
+ </xsl:variable>
+ <xsl:variable name="fname2">
+ <xsl:value-of select="substring-after($fname1, 'erlang:')"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length($fname2) > 0">
+ <xsl:value-of select="$fname2"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$fname1"/>
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
-
+
<li title="{$fname}-{$arity}">
- <a href="{$basename}.html#{$fname}-{$arity}">
+ <a href="{$basename}.html#{$fname}-{$arity}">
<xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
</a>
- </li>
+ </li>
</xsl:when>
</xsl:choose>
-
+
</xsl:for-each>
</xsl:template>
@@ -1148,7 +1471,7 @@
<!-- Func -->
<xsl:template match="func">
<xsl:param name="partnum"/>
-
+
<p><xsl:apply-templates select="name"/></p>
<xsl:apply-templates select="fsummary|type|desc">
@@ -1159,33 +1482,48 @@
<xsl:template match="name">
+ <xsl:choose>
+ <!-- @arity is mandatory when referring to a specification -->
+ <xsl:when test="string-length(@arity) > 0">
+ <xsl:call-template name="spec_name"/>
+ </xsl:when>
+ <xsl:when test="ancestor::datatype">
+ <xsl:call-template name="type_name"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="name">
<xsl:variable name="tmpstring">
<xsl:value-of select="substring-before(substring-after(., '('), '->')"/>
- </xsl:variable>
+ </xsl:variable>
<xsl:variable name="ustring">
<xsl:choose>
<xsl:when test="string-length($tmpstring) > 0">
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="$tmpstring"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="substring-after(., '(')"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:otherwise>
</xsl:choose>
- </xsl:variable>
-
+ </xsl:variable>
+
<xsl:variable name="arity">
<xsl:call-template name="calc-arity">
<xsl:with-param name="string" select="substring-before($ustring, ')')"/>
- <xsl:with-param name="no-of-pars" select="0"/>
+ <xsl:with-param name="no-of-pars" select="0"/>
</xsl:call-template>
- </xsl:variable>
-
+ </xsl:variable>
+
<xsl:choose>
<xsl:when test="ancestor::cref">
<a name="{substring-before(nametext, '(')}"><span class="bold_code"><xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/></span></a><br/>
@@ -1199,7 +1537,7 @@
<xsl:value-of select="substring-after($fname1, 'erlang:')"/>
</xsl:variable>
<xsl:choose>
- <xsl:when test="string-length($fname2) > 0">
+ <xsl:when test="string-length($fname2) > 0">
<xsl:value-of select="$fname2"/>
</xsl:when>
<xsl:otherwise>
@@ -1213,21 +1551,20 @@
<span class="bold_code"><xsl:value-of select="."/></span>
</xsl:otherwise>
</xsl:choose>
-
- </xsl:template>
+ </xsl:template>
<!-- Type -->
<xsl:template match="type">
<xsl:param name="partnum"/>
- <div class="REFBODY"><p>Types:</p>
+ <div class="REFBODY"><p>Types:</p>
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
</div>
-
+
</xsl:template>
@@ -1286,16 +1623,37 @@
<xsl:variable name="modulepart"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable>
<xsl:choose>
<xsl:when test="string-length($modulepart) > 0">
- <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable>
+ <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable>
<span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html#{$linkpart}');"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
+ <!-- Dialyzer seealso (the application is unknown) -->
+ <xsl:when test="string-length($specs_file) > 0
+ and count($i/specs/module[@name=$filepart]) = 0">
+ <!-- Deemed to slow; use key() instead
+ <xsl:variable name="app"
+ select="$m2a/mod2app/module[@name=$filepart]"/>
+ -->
+ <xsl:variable name="reftext" select="text()"/>
+ <xsl:for-each select="$m2a">
+ <xsl:variable name="app" select="key('mod2app', $filepart)"/>
+ <xsl:choose>
+ <xsl:when test="string-length($app) > 0">
+ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html');"><xsl:value-of select="$reftext"/></a></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- Unknown application; no link -->
+ <xsl:value-of select="$reftext"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:when>
<xsl:when test="string-length($linkpart) > 0">
<span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span>
</xsl:when>
- <xsl:otherwise>
- <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span>
+ <xsl:otherwise>
+ <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
@@ -1308,16 +1666,16 @@
</xsl:when>
<xsl:otherwise>
<xsl:variable name="modulepart"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable>
-
+
<xsl:choose>
<xsl:when test="string-length($modulepart) > 0">
- <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable>
+ <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable>
<span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html');"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
- <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
+ <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
</xsl:otherwise>
- </xsl:choose>
+ </xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
@@ -1342,16 +1700,16 @@
<xsl:choose>
<xsl:when test="ancestor::parts">
<a href="users_guide_glossary.html#{@id}"><xsl:value-of select="@id"/></a>
- </xsl:when>
- <xsl:when test="ancestor::applications">
+ </xsl:when>
+ <xsl:when test="ancestor::applications">
<a href="ref_man_glossary.html#{@id}"><xsl:value-of select="@id"/></a>
- </xsl:when>
+ </xsl:when>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<a href="{$topdocdir}/glossary.html#{@id}"><xsl:value-of select="@id"/></a>
</xsl:otherwise>
- </xsl:choose -->
+ </xsl:choose -->
</xsl:template>
<xsl:template match="cite">
@@ -1375,9 +1733,9 @@
<center><h4>Version <xsl:value-of select="$appver"/></h4></center>
<center><h4><xsl:value-of select="$gendate"/></h4></center>
-
+
<xsl:apply-templates select="chapter"/>
-
+
</xsl:template>
<!-- Menu.rn -->
@@ -1410,7 +1768,7 @@
</xsl:call-template>
</ul>
</div>
- </div>
+ </div>
</xsl:template>
<!-- Glossary -->
@@ -1423,14 +1781,14 @@
<title>Erlang Documentation -- <xsl:value-of select="header/title"/></title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
-
+
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
<!-- Generate menu -->
<xsl:call-template name="menu"/>
-
+
<div id="content">
<div class="innertube">
<h1>Glossary</h1>
@@ -1478,14 +1836,14 @@
<title>Erlang Documentation -- <xsl:value-of select="header/title"/></title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
-
+
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
<!-- Generate menu -->
<xsl:call-template name="menu"/>
-
+
<div id="content">
<div class="innertube">
<h1>Bibliography</h1>
@@ -1498,8 +1856,8 @@
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="citedef"/></td>
- </tr>
- </xsl:if>
+ </tr>
+ </xsl:if>
</xsl:for-each>
</table>
@@ -1529,7 +1887,7 @@
<xsl:template name="calc-arity">
<xsl:param name="string"/>
<xsl:param name="no-of-pars"/>
-
+
<xsl:variable name="length">
<xsl:value-of select="string-length($string)"/>
</xsl:variable>
@@ -1538,8 +1896,8 @@
<xsl:when test="$length > 0">
<xsl:call-template name="calc-arity">
<xsl:with-param name="string" select="substring-after($string, ',')"/>
- <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/>
- </xsl:call-template>
+ <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$no-of-pars"/>
@@ -1554,9 +1912,9 @@
<xsl:variable name="str1">
<xsl:call-template name="remove-paren-1">
<xsl:with-param name="string" select="$string"/>
- <xsl:with-param name="start">(</xsl:with-param>
- <xsl:with-param name="end">)</xsl:with-param>
- </xsl:call-template>
+ <xsl:with-param name="start">(</xsl:with-param>
+ <xsl:with-param name="end">)</xsl:with-param>
+ </xsl:call-template>
</xsl:variable>
<xsl:variable name="str2">
@@ -1564,7 +1922,7 @@
<xsl:with-param name="string" select="$str1"/>
<xsl:with-param name="start">{</xsl:with-param>
<xsl:with-param name="end">}</xsl:with-param>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:variable name="str3">
@@ -1572,7 +1930,7 @@
<xsl:with-param name="string" select="$str2"/>
<xsl:with-param name="start">[</xsl:with-param>
<xsl:with-param name="end">]</xsl:with-param>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:value-of select="$str3"/>
@@ -1584,7 +1942,7 @@
<xsl:param name="string"/>
<xsl:param name="start"/>
<xsl:param name="end"/>
-
+
<xsl:variable name="tmp1">
<xsl:value-of select="substring-before($string, $start)"/>
</xsl:variable>
@@ -1597,7 +1955,7 @@
<xsl:variable name="retstring">
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="$tmp2"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat(concat($tmp1, 'x'), $retstring)"/>
</xsl:when>
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index 71c4a66707..2a8fb9fe3e 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
+<!--
#
# %CopyrightBegin%
#
@@ -17,24 +17,294 @@
# under the License.
#
# %CopyrightEnd%
-
+
-->
<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:preserve-space elements="code pre"/>
<xsl:strip-space elements="*"/>
<xsl:output method="text" encoding="UTF-8" indent="no"/>
+ <!-- Start of Dialyzer type/spec tags. See also the template matching "name"
+ -->
+
+ <!-- Note: specs data for *one* module (as opposed to html and pdf) -->
+ <xsl:param name="specs_file" select="''"/>
+ <xsl:variable name="i" select="document($specs_file)"></xsl:variable>
+
+ <xsl:template name="err">
+ <xsl:param name="m"/>
+ <xsl:param name="n"/>
+ <xsl:param name="a"/>
+ <xsl:param name="s"/>
+ <xsl:message terminate="yes">
+ Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of
+ select="$n"/>/<xsl:value-of
+ select="$a"/>: <xsl:value-of select="$s"/>
+ </xsl:message>
+ </xsl:template>
+
+ <xsl:template name="spec_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="clause" select="@clause"/>
+ <xsl:variable name="spec0" select=
+ "$i/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec" select="$spec0[string-length($clause) = 0
+ or position() = $clause]"/>
+ <xsl:if test="count($spec) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown spec</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:message terminate="yes">
+ Error: did not expect a 'name' tag with name/arity attributes here!
+ </xsl:message>
+ </xsl:when>
+ <xsl:when test="ancestor::erlref">
+ <xsl:choose>
+ <xsl:when test="string(@with_guards) = 'no'">
+ <xsl:apply-templates select="$spec/contract/clause/head"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="contract">
+ <xsl:with-param name="contract" select="$spec/contract"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>&#10;.br</xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="contract">
+ <xsl:param name="contract"/>
+ <xsl:call-template name="clause">
+ <xsl:with-param name="clause" select="$contract/clause"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="clause">
+ <xsl:param name="clause"/>
+ <xsl:variable name="type_desc" select="../type_desc"/>
+ <xsl:for-each select="$clause">
+ <xsl:apply-templates select="head"/>
+ <xsl:if test="count(guard) > 0">
+ <xsl:call-template name="guard">
+ <xsl:with-param name="guard" select="guard"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="head">
+ <xsl:text>&#10;.nf&#10;</xsl:text>
+ <xsl:text>&#10;.B&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.fi</xsl:text>
+ </xsl:template>
+
+ <xsl:template name="guard">
+ <xsl:param name="guard"/>
+ <xsl:param name="type_desc"/>
+ <xsl:text>&#10;.RS</xsl:text>
+ <xsl:text>&#10;.TP</xsl:text>
+ <xsl:text>&#10;Types</xsl:text>
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ <xsl:text>&#10;.RE</xsl:text>
+ </xsl:template>
+
+ <xsl:template name="subtype">
+ <xsl:param name="subtype"/>
+ <xsl:param name="type_desc"/>
+ <xsl:for-each select="$subtype">
+ <xsl:variable name="tname" select="typename"/>
+ <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="string"/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- Note: <type_desc> has not been implemented for data types. -->
+
+ <!-- Similar to <d> -->
+ <xsl:template match="type_desc">
+ <xsl:text>&#10;</xsl:text><xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ </xsl:template>
+
+ <!-- Datatypes -->
+ <xsl:template match="datatypes">
+ <xsl:text>&#10;.SH DATA TYPES</xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Datatype -->
+ <xsl:template match="datatype">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="typehead">
+ <xsl:text>&#10;.nf&#10;</xsl:text>
+ <xsl:text>&#10;.B&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.fi</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="local_defs">
+ <xsl:text>&#10;.RS</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.RE</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="local_def">
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ </xsl:template>
+
+ <xsl:template name="type_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length(@n_vars) > 0">
+ <xsl:value-of select="@n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="string-length($name) > 0">
+ <xsl:variable name="type" select=
+ "$i/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]"/>
+
+ <xsl:if test="count($type) != 1">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n_vars"/>
+ <xsl:with-param name="s">unknown type</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>&#10;.nf&#10;</xsl:text>
+ <xsl:text>&#10;.B&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.fi</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Used both in <datatype> and in <func>! -->
+ <xsl:template match="anno">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="anno" select="normalize-space(text())"/>
+ <xsl:variable name="namespec"
+ select="ancestor::desc/preceding-sibling::name"/>
+ <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>)
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:variable name="mod" select="$namespec/@mod"/>
+ <xsl:variable name="name" select="$namespec/@name"/>
+ <xsl:variable name="arity" select="$namespec/@arity"/>
+ <xsl:variable name="clause" select="$namespec/@clause"/>
+ <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length($tmp_n_vars) > 0">
+ <xsl:value-of select="$tmp_n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0" select=
+ "$i/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec_annos" select=
+ "$spec0[string-length($clause) = 0
+ or position() = $clause]/anno[.=$anno]"/>
+ <xsl:variable name="type_annos" select=
+ "$i/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/>
+
+ <xsl:if test="count($spec_annos) = 0
+ and count($type_annos) = 0
+ and string-length($specs_file) > 0">
+ <xsl:variable name="n">
+ <xsl:choose>
+ <xsl:when test="string-length($arity) = 0">
+ <xsl:value-of select="$n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$arity"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n"/>
+ <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:value-of select="$anno"/>
+ </xsl:template>
+
+ <!-- Used for indentation of formatted types and specs -->
+ <xsl:template match="nbsp">
+ <xsl:text> </xsl:text>
+ </xsl:template>
+
+ <!-- End of Dialyzer type/spec tags -->
+
<!-- Header -->
<xsl:template match="header">
</xsl:template>
-
+
<!-- Section/Title -->
<xsl:template match="section/title">
</xsl:template>
-
+
<!-- *ref/Section -->
<xsl:template match="erlref/section|comref/section|cref/section|fileref/section|appref/section">
<xsl:text>&#10;.SH "</xsl:text><xsl:value-of select="translate(title, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:text>"&#10;</xsl:text>
@@ -49,11 +319,11 @@
<!-- Lists -->
-
+
<xsl:template match="list">
<xsl:text>&#10;.RS 2</xsl:text>
<xsl:apply-templates/>
- <xsl:text>&#10;.RE</xsl:text>
+ <xsl:text>&#10;.RE&#10;</xsl:text>
</xsl:template>
<xsl:template match="list/item">
@@ -66,9 +336,9 @@
<xsl:template match="taglist">
<xsl:text>&#10;.RS 2</xsl:text>
<xsl:apply-templates select="tag|item"/>
- <xsl:text>&#10;.RE</xsl:text>
+ <xsl:text>&#10;.RE&#10;</xsl:text>
</xsl:template>
-
+
<xsl:template match="taglist/tag">
<xsl:text>&#10;.TP 2&#10;</xsl:text>
<xsl:text>.B&#10;</xsl:text>
@@ -76,7 +346,7 @@
</xsl:template>
<xsl:template match="taglist/item">
- <xsl:apply-templates/>
+ <xsl:apply-templates/>
</xsl:template>
<xsl:template match="item/p">
@@ -88,10 +358,10 @@
<xsl:value-of select="$content"/>
</xsl:when>
<xsl:otherwise>
- <xsl:text>&#10;.RS 2</xsl:text>
- <xsl:text>&#10;.LP&#10;&#10;.LP&#10;</xsl:text>
+ <xsl:text>&#10;.RS 2</xsl:text>
+ <xsl:text>&#10;.LP&#10;&#10;.LP&#10;</xsl:text>
<xsl:value-of select="$content"/>
- <xsl:text>&#10;.RE</xsl:text>
+ <xsl:text>&#10;.RE</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
@@ -171,7 +441,7 @@
<xsl:template match="application">
<xsl:apply-templates/>
</xsl:template>
-
+
<!-- Erlref -->
<xsl:template match="/erlref">
<xsl:variable name="companyname">
@@ -184,7 +454,7 @@
<xsl:text>.TH </xsl:text><xsl:value-of select="module"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Module Definition"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
- <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text>&#10;</xsl:text>
+ <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
@@ -199,7 +469,7 @@
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="com"/><xsl:text> 1 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "User Commands"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
- <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text>&#10;</xsl:text>
+ <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
@@ -214,7 +484,7 @@
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="lib"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "C Library Functions"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
- <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text>&#10;</xsl:text>
+ <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
@@ -229,7 +499,7 @@
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="file"/><xsl:text> 5 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Files"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
- <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text>&#10;</xsl:text>
+ <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
@@ -244,7 +514,7 @@
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="app"/><xsl:text> 7 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Application Definition"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
- <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text>&#10;</xsl:text>
+ <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
@@ -271,10 +541,26 @@
<!-- Func -->
<xsl:template match="func">
<xsl:text>&#10;.LP</xsl:text>
- <xsl:apply-templates/>
+ <xsl:apply-templates select="name"/>
+ <xsl:apply-templates select="fsummary|type|desc"/>
</xsl:template>
<xsl:template match="name">
+ <xsl:choose>
+ <!-- @arity is mandatory when referring to a specification -->
+ <xsl:when test="string-length(@arity) > 0">
+ <xsl:call-template name="spec_name"/>
+ </xsl:when>
+ <xsl:when test="ancestor::datatype">
+ <xsl:call-template name="type_name"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="name">
<xsl:text>&#10;.B&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;.br</xsl:text>
@@ -296,7 +582,7 @@
<xsl:text>&#10;</xsl:text><xsl:value-of select="normalize-space(text())"/>
<xsl:text>&#10;.br</xsl:text>
</xsl:template>
-
+
<!-- D -->
<xsl:template match="d">
<xsl:text>&#10;</xsl:text><xsl:apply-templates/>
@@ -316,7 +602,7 @@
<!-- This tag is skipped for now. -->
</xsl:template>
-
+
<!-- Authors -->
<xsl:template match="authors">
<xsl:text>&#10;.SH AUTHORS</xsl:text>
@@ -338,19 +624,26 @@
<!-- Do not noramlize any text within pre and code tags. -->
<xsl:template match="pre/text()">
- <xsl:value-of select="."/>
+ <xsl:call-template name="replace-string">
+ <xsl:with-param name="text" select="." />
+ <xsl:with-param name="replace" select="&quot;\&quot;" />
+ <xsl:with-param name="with" select="&quot;\\&quot;" />
+ </xsl:call-template>
</xsl:template>
<xsl:template match="code/text()">
- <xsl:value-of select="."/>
+ <xsl:call-template name="replace-string">
+ <xsl:with-param name="text" select="." />
+ <xsl:with-param name="replace" select="&quot;\&quot;" />
+ <xsl:with-param name="with" select="&quot;\\&quot;" />
+ </xsl:call-template>
</xsl:template>
-
<!-- Replace ' by \&' ans . by \&. -->
<xsl:template match="text()">
<xsl:variable name="startstring">
<xsl:value-of select="normalize-space()"/><xsl:text> </xsl:text>
- </xsl:variable>
+ </xsl:variable>
<xsl:variable name="rep1">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$startstring" />
diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl
index e12b4d219a..1e80c360b8 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
+<!--
#
# %CopyrightBegin%
#
@@ -17,7 +17,7 @@
# under the License.
#
# %CopyrightEnd%
-
+
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
@@ -27,16 +27,310 @@
<xsl:include href="db_pdf_params.xsl"/>
+ <!-- Start of Dialyzer type/spec tags.
+ See also the template matching "name" and the template "bookmarks6"
+ -->
+
+ <xsl:param name="specs_file" select="''"/>
+ <xsl:variable name="i" select="document($specs_file)"></xsl:variable>
+
+ <xsl:template name="err">
+ <xsl:param name="m"/>
+ <xsl:param name="n"/>
+ <xsl:param name="a"/>
+ <xsl:param name="s"/>
+ <xsl:message terminate="yes">
+ Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of
+ select="$n"/>/<xsl:value-of
+ select="$a"/>: <xsl:value-of select="$s"/>
+ </xsl:message>
+ </xsl:template>
+
+ <xsl:template name="spec_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="clause" select="@clause"/>
+ <xsl:variable name="spec0" select=
+ "$i/specs/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec" select="$spec0[string-length($clause) = 0
+ or position() = $clause]"/>
+ <xsl:if test="count($spec) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown spec</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:message terminate="yes">
+ Error: did not expect a 'name' tag with name/arity attributes here!
+ </xsl:message>
+ </xsl:when>
+ <xsl:when test="ancestor::erlref">
+ <fo:block id="{generate-id()}">
+ <xsl:choose>
+ <xsl:when test="string(@with_guards) = 'no'">
+ <xsl:apply-templates select="$spec/contract/clause/head"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="contract">
+ <xsl:with-param name="contract" select="$spec/contract"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </fo:block>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="contract">
+ <xsl:param name="contract"/>
+ <xsl:call-template name="clause">
+ <xsl:with-param name="clause" select="$contract/clause"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="clause">
+ <xsl:param name="clause"/>
+ <xsl:variable name="type_desc" select="../type_desc"/>
+ <xsl:for-each select="$clause">
+ <xsl:apply-templates select="head"/>
+ <xsl:if test="count(guard) > 0">
+ <xsl:call-template name="guard">
+ <xsl:with-param name="guard" select="guard"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="head">
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates/>
+ </fo:block>
+ </xsl:template>
+
+ <xsl:template name="guard">
+ <fo:block>
+ <xsl:text>Types:</xsl:text>
+ </fo:block>
+ <fo:list-block xsl:use-attribute-sets="type-listblock">
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </fo:list-block>
+ </xsl:template>
+
+ <xsl:template name="subtype">
+ <xsl:param name="subtype"/>
+ <xsl:param name="type_desc"/>
+ <xsl:for-each select="$subtype">
+ <xsl:variable name="tname" select="typename"/>
+ <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/>
+ <fo:list-item xsl:use-attribute-sets="type-listitem">
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block>
+ </fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()" format="justify">
+ <fo:block font-weight="bold">
+ <xsl:apply-templates select="string"/>
+ </fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- Note: <type_desc> has not been implemented for data types. -->
+
+ <!-- Similar to <d> -->
+ <xsl:template match="type_desc">
+ <fo:list-item xsl:use-attribute-sets="type-listitem">
+ <fo:list-item-label end-indent="label-end()"><fo:block></fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()" format="justify">
+ <fo:block>
+ <xsl:apply-templates/>
+ </fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </xsl:template>
+
+ <!-- Datatypes -->
+ <xsl:template match="datatypes">
+ <fo:block xsl:use-attribute-sets="h3">
+ <xsl:text>Data Types</xsl:text>
+ </fo:block>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Datatype -->
+ <xsl:template match="datatype">
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates select="name"/>
+ </fo:block>
+ <xsl:apply-templates select="desc"/>
+ </xsl:template>
+
+ <!-- Like <head>... -->
+ <xsl:template match="typehead">
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates/>
+ </fo:block>
+ </xsl:template>
+
+ <!-- Like <guard>, except "Types:"... -->
+ <xsl:template match="local_defs">
+ <fo:list-block xsl:use-attribute-sets="type-listblock">
+ <xsl:apply-templates/>
+ </fo:list-block>
+ </xsl:template>
+
+ <!-- Like <subtype>... -->
+ <xsl:template match="local_def">
+ <fo:list-item xsl:use-attribute-sets="type-listitem">
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block>
+ </fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()" format="justify">
+ <fo:block font-weight="bold">
+ <xsl:apply-templates/>
+ </fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </xsl:template>
+
+ <xsl:template name="type_name">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length(@n_vars) > 0">
+ <xsl:value-of select="@n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="string-length($name) > 0">
+ <xsl:variable name="type" select=
+ "$i/specs/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]"/>
+
+ <xsl:if test="count($type) != 1">
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n_vars"/>
+ <xsl:with-param name="s">unknown type</xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <fo:inline font-weight="bold" xsl:use-attribute-sets="type-listitem">
+ <xsl:value-of select="."/>
+ </fo:inline>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Used both in <datatype> and in <func>! -->
+ <xsl:template match="anno">
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="anno" select="normalize-space(text())"/>
+ <xsl:variable name="namespec"
+ select="ancestor::desc/preceding-sibling::name"/>
+ <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>)
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:variable name="mod" select="$namespec/@mod"/>
+ <xsl:variable name="name" select="$namespec/@name"/>
+ <xsl:variable name="arity" select="$namespec/@arity"/>
+ <xsl:variable name="clause" select="$namespec/@clause"/>
+ <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/>
+ <xsl:variable name="n_vars">
+ <xsl:choose>
+ <xsl:when test="string-length($tmp_n_vars) > 0">
+ <xsl:value-of select="$tmp_n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0" select=
+ "$i/specs/module[@name=$curModule]/spec
+ [name=$name and arity=$arity
+ and (string-length($mod) = 0 or module = $mod)]"/>
+ <xsl:variable name="spec_annos" select=
+ "$spec0[string-length($clause) = 0
+ or position() = $clause]/anno[.=$anno]"/>
+ <xsl:variable name="type_annos" select=
+ "$i/specs/module[@name=$curModule]/type
+ [name=$name and n_vars=$n_vars
+ and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/>
+
+ <xsl:if test="count($spec_annos) = 0
+ and count($type_annos) = 0
+ and string-length($specs_file) > 0">
+ <xsl:variable name="n">
+ <xsl:choose>
+ <xsl:when test="string-length($arity) = 0">
+ <xsl:value-of select="$n_vars"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$arity"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:call-template name="err">
+ <xsl:with-param name="m" select="$mod"/>
+ <xsl:with-param name="n" select="$name"/>
+ <xsl:with-param name="a" select="$n"/>
+ <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:value-of select="$anno"/>
+ </xsl:template>
+
+ <!-- Used for indentation of formatted types and specs -->
+ <xsl:template match="nbsp">
+ <xsl:text>&#160;</xsl:text>
+ </xsl:template>
+
+ <!-- End of Dialyzer type/spec tags -->
<xsl:template match="/">
<xsl:apply-templates select="book"/>
</xsl:template>
-
+
<xsl:template match="book">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
- <!-- Master pages -->
+ <!-- Master pages -->
<fo:layout-master-set>
<fo:simple-page-master
master-name="cover"
@@ -47,7 +341,7 @@
<xsl:attribute name="page-width">
<xsl:value-of select="$page-width"/>
</xsl:attribute>
- <fo:region-body
+ <fo:region-body
margin="0mm"/>
</fo:simple-page-master>
@@ -63,7 +357,7 @@
<xsl:attribute name="page-width">
<xsl:value-of select="$page-width"/>
</xsl:attribute>
- <fo:region-body
+ <fo:region-body
margin-top="15mm"
margin-bottom="20mm"/>
<fo:region-before
@@ -100,10 +394,10 @@
<fo:page-sequence-master master-name="document">
<fo:repeatable-page-master-alternatives>
- <fo:conditional-page-master-reference
+ <fo:conditional-page-master-reference
master-reference="left-page"
odd-or-even="even"/>
- <fo:conditional-page-master-reference
+ <fo:conditional-page-master-reference
master-reference="right-page"
odd-or-even="odd"/>
</fo:repeatable-page-master-alternatives>
@@ -166,7 +460,7 @@
<fo:flow flow-name="xsl-region-body">
<fo:block>
-
+
</fo:block>
<xsl:apply-templates select="parts"/>
@@ -189,7 +483,7 @@
<!-- Cover page -->
<xsl:template match="header/title">
- <fo:page-sequence
+ <fo:page-sequence
font-family="sans-serif"
force-page-count="even"
master-reference="cover">
@@ -242,7 +536,7 @@
the License for the specific language governing rights and limitations
under the License.
- The Initial Developer of the Original Code is
+ The Initial Developer of the Original Code is
-->
<xsl:value-of select="$companyname"/>.
</fo:block>
@@ -281,22 +575,22 @@
<xsl:template name="bookmarks1">
<xsl:param name="entries"/>
<xsl:if test="$entries != ''">
-
+
<fo:bookmark internal-destination="{generate-id(/book/parts/part)}"
starting-state="hide">
<fo:bookmark-title>User's Guide</fo:bookmark-title>
-
+
<xsl:for-each select="$entries">
<xsl:call-template name="bookmarks2">
<xsl:with-param name="entries"
select="chapter[header/title]"/>
</xsl:call-template>
</xsl:for-each>
-
+
</fo:bookmark>
</xsl:if>
</xsl:template>
-
+
<xsl:template name="bookmarks2">
<xsl:param name="entries"/>
<xsl:for-each select="$entries">
@@ -341,7 +635,7 @@
starting-state="hide">
<fo:bookmark-title>Reference Manual</fo:bookmark-title>
<xsl:for-each select="$entries">
-
+
<xsl:call-template name="bookmarks5">
<xsl:with-param name="entries"
select="erlref[module]|comref[com]|cref[lib]|fileref[file]|appref[app]"/>
@@ -387,7 +681,7 @@
<fo:bookmark internal-destination="{generate-id(nametext)}" starting-state="hide">
<xsl:variable name="fname">
<xsl:value-of select="substring-before(nametext, '(')"/>
- </xsl:variable>
+ </xsl:variable>
<fo:bookmark-title>
<xsl:choose>
<xsl:when test="string-length($fname) > 0">
@@ -396,7 +690,7 @@
<xsl:otherwise>
<xsl:value-of select="nametext"/>()
</xsl:otherwise>
- </xsl:choose>
+ </xsl:choose>
</fo:bookmark-title>
</fo:bookmark>
</xsl:when>
@@ -404,60 +698,76 @@
<fo:bookmark internal-destination="{generate-id(.)}" starting-state="hide">
<xsl:variable name="tmpstring">
<xsl:value-of select="substring-before(substring-after(., '('), '->')"/>
- </xsl:variable>
+ </xsl:variable>
<xsl:variable name="ustring">
<xsl:choose>
<xsl:when test="string-length($tmpstring) > 0">
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="$tmpstring"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="substring-after(., '(')"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:otherwise>
</xsl:choose>
- </xsl:variable>
+ </xsl:variable>
<xsl:variable name="arity">
- <xsl:call-template name="calc-arity">
- <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
- <xsl:with-param name="no-of-pars" select="0"/>
- </xsl:call-template>
- </xsl:variable>
-
- <xsl:variable name="fname">
- <xsl:variable name="fname1">
- <xsl:value-of select="substring-before(., '(')"/>
- </xsl:variable>
- <xsl:variable name="fname2">
- <xsl:value-of select="substring-after($fname1, 'erlang:')"/>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="string-length($fname2) > 0">
- <xsl:value-of select="$fname2"/>
- </xsl:when>
+ <xsl:choose>
+ <xsl:when test="string-length(@arity) > 0">
+ <!-- Dialyzer spec -->
+ <xsl:value-of select="@arity"/>
+ </xsl:when>
<xsl:otherwise>
- <xsl:value-of select="$fname1"/>
+ <xsl:call-template name="calc-arity">
+ <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
+ <xsl:with-param name="no-of-pars" select="0"/>
+ </xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
+ <xsl:variable name="fname">
+ <xsl:choose>
+ <xsl:when test="string-length(@name) > 0">
+ <!-- Dialyzer spec -->
+ <xsl:value-of select="@name"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="fname1">
+ <xsl:value-of select="substring-before(., '(')"/>
+ </xsl:variable>
+ <xsl:variable name="fname2">
+ <xsl:value-of select="substring-after($fname1, 'erlang:')"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length($fname2) > 0">
+ <xsl:value-of select="$fname2"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$fname1"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
<fo:bookmark-title>
<xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
</fo:bookmark-title>
</fo:bookmark>
</xsl:when>
</xsl:choose>
-
+
</xsl:for-each>
</xsl:template>
<!-- UG part -->
-
+
<!-- Parts -->
<xsl:template match="parts">
<xsl:apply-templates select="part"/>
@@ -491,7 +801,7 @@
<xsl:value-of select="$partnum"/>.<xsl:number/>&#160;&#160;<xsl:value-of select="header/title"/>
</fo:marker>
<xsl:value-of select="$partnum"/>.<xsl:number/>&#160;&#160;<xsl:value-of select="header/title"/>
-
+
</fo:block>
<xsl:apply-templates select="section|quote|warning|note|br|image|marker|table|p|pre|code|list|taglist|codeinclude|erleval">
@@ -567,7 +877,7 @@
</xsl:template>
<!-- Lists -->
-
+
<xsl:template match="list">
<xsl:param name="partnum"/>
<fo:list-block xsl:use-attribute-sets="listblock">
@@ -692,7 +1002,7 @@
</xsl:variable>
<fo:block xsl:use-attribute-sets="code">
- <xsl:apply-templates select="text()"/>
+ <xsl:apply-templates select="text()"/>
</fo:block>
<xsl:if test="@caption">
@@ -711,7 +1021,7 @@
</xsl:variable>
<fo:block xsl:use-attribute-sets="code">
- <xsl:apply-templates/>
+ <xsl:apply-templates/>
</fo:block>
<xsl:if test="@caption">
@@ -734,23 +1044,23 @@
<xsl:variable name="partnum">
<xsl:number level="any" from="book" count="part|application"/>
</xsl:variable>
-
- <fo:block xsl:use-attribute-sets="h1" id="{generate-id()}">
+
+ <fo:block xsl:use-attribute-sets="h1" id="{generate-id()}">
<xsl:if test="/book/header/title">
<xsl:value-of select="$partnum"/>&#160;&#160;&#160;
<xsl:text>Reference Manual</xsl:text>
- </xsl:if>
+ </xsl:if>
</fo:block>
-
-
+
+
<xsl:apply-templates select="description">
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
-
+
<xsl:apply-templates select="erlref|comref|cref|fileref|appref">
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
-
+
</xsl:template>
<!-- Erlref -->
@@ -763,7 +1073,7 @@
<fo:marker marker-class-name="chapter-title">
<xsl:value-of select="module"/>
</fo:marker>
- <xsl:value-of select="module"/>
+ <xsl:value-of select="module"/>
</fo:block>
<xsl:text>Erlang module</xsl:text>
</fo:block>
@@ -784,7 +1094,7 @@
<fo:marker marker-class-name="chapter-title">
<xsl:value-of select="com"/>
</fo:marker>
- <xsl:value-of select="com"/>
+ <xsl:value-of select="com"/>
</fo:block>
<xsl:text>Command</xsl:text>
</fo:block>
@@ -805,7 +1115,7 @@
<fo:marker marker-class-name="chapter-title">
<xsl:value-of select="lib"/>
</fo:marker>
- <xsl:value-of select="lib"/>
+ <xsl:value-of select="lib"/>
</fo:block>
<xsl:text>C Library</xsl:text>
</fo:block>
@@ -826,7 +1136,7 @@
<fo:marker marker-class-name="chapter-title">
<xsl:value-of select="file"/>
</fo:marker>
- <xsl:value-of select="file"/>
+ <xsl:value-of select="file"/>
</fo:block>
<xsl:text>Name</xsl:text>
</fo:block>
@@ -847,7 +1157,7 @@
<fo:marker marker-class-name="chapter-title">
<xsl:value-of select="app"/>
</fo:marker>
- <xsl:value-of select="app"/>
+ <xsl:value-of select="app"/>
</fo:block>
<xsl:text>Application</xsl:text>
</fo:block>
@@ -900,9 +1210,7 @@
<xsl:template match="func">
<xsl:param name="partnum"/>
- <fo:block xsl:use-attribute-sets="function-name">
- <xsl:apply-templates select="name"/>
- </fo:block>
+ <xsl:apply-templates select="name"/>
<xsl:apply-templates select="fsummary|type|desc">
<xsl:with-param name="partnum" select="$partnum"/>
@@ -914,15 +1222,35 @@
<xsl:template match="name">
<xsl:param name="partnum"/>
<xsl:choose>
+ <!-- @arity is mandatory when referring to a specification -->
+ <xsl:when test="string-length(@arity) > 0">
+ <xsl:call-template name="spec_name"/>
+ </xsl:when>
+ <xsl:when test="ancestor::datatype">
+ <xsl:call-template name="type_name"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:call-template name="name">
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:call-template>
+ </fo:block>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="name">
+ <xsl:param name="partnum"/>
+ <xsl:choose>
<xsl:when test="ancestor::cref">
<fo:block id="{generate-id(nametext)}">
- <xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/>
- </fo:block>
+ <xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/>
+ </fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block id="{generate-id(.)}">
- <xsl:value-of select="."/>
- </fo:block>
+ <xsl:value-of select="."/>
+ </fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
@@ -931,9 +1259,9 @@
<!-- Type -->
<xsl:template match="type">
<xsl:param name="partnum"/>
-
+
<fo:block>
- <xsl:text>Types:</xsl:text>
+ <xsl:text>Types:</xsl:text>
</fo:block>
<fo:list-block xsl:use-attribute-sets="type-listblock">
@@ -1001,9 +1329,9 @@
<xsl:param name="chapnum"/>
<xsl:variable name="tabnum">
<xsl:number level="any" from="chapter" count="table"/>
- </xsl:variable>
+ </xsl:variable>
<fo:table xsl:use-attribute-sets="table">
- <fo:table-body>
+ <fo:table-body>
<xsl:apply-templates select="row">
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="tabnum" select="$tabnum"/>
@@ -1107,7 +1435,7 @@
<xsl:template name="calc-arity">
<xsl:param name="string"/>
<xsl:param name="no-of-pars"/>
-
+
<xsl:variable name="length">
<xsl:value-of select="string-length($string)"/>
</xsl:variable>
@@ -1116,8 +1444,8 @@
<xsl:when test="$length > 0">
<xsl:call-template name="calc-arity">
<xsl:with-param name="string" select="substring-after($string, ',')"/>
- <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/>
- </xsl:call-template>
+ <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$no-of-pars"/>
@@ -1131,9 +1459,9 @@
<xsl:variable name="str1">
<xsl:call-template name="remove-paren-1">
<xsl:with-param name="string" select="$string"/>
- <xsl:with-param name="start">(</xsl:with-param>
- <xsl:with-param name="end">)</xsl:with-param>
- </xsl:call-template>
+ <xsl:with-param name="start">(</xsl:with-param>
+ <xsl:with-param name="end">)</xsl:with-param>
+ </xsl:call-template>
</xsl:variable>
<xsl:variable name="str2">
@@ -1141,7 +1469,7 @@
<xsl:with-param name="string" select="$str1"/>
<xsl:with-param name="start">{</xsl:with-param>
<xsl:with-param name="end">}</xsl:with-param>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:variable name="str3">
@@ -1149,7 +1477,7 @@
<xsl:with-param name="string" select="$str2"/>
<xsl:with-param name="start">[</xsl:with-param>
<xsl:with-param name="end">]</xsl:with-param>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:value-of select="$str3"/>
@@ -1161,7 +1489,7 @@
<xsl:param name="string"/>
<xsl:param name="start"/>
<xsl:param name="end"/>
-
+
<xsl:variable name="tmp1">
<xsl:value-of select="substring-before($string, $start)"/>
</xsl:variable>
@@ -1174,7 +1502,7 @@
<xsl:variable name="retstring">
<xsl:call-template name="remove-paren">
<xsl:with-param name="string" select="$tmp2"/>
- </xsl:call-template>
+ </xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat(concat($tmp1, 'x'), $retstring)"/>
</xsl:when>
diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile
new file mode 100644
index 0000000000..8e81bccd59
--- /dev/null
+++ b/lib/erl_docgen/src/Makefile
@@ -0,0 +1,96 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-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%
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(ERL_DOCGEN_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/erl_docgen-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+MODULES = \
+ otp_specs
+
+HRL_FILES =
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
+
+APP_FILE = erl_docgen.app
+
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+APPUP_FILE = erl_docgen.appup
+
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -I../../xmerl/include
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+docs:
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+
+release_docs_spec:
+
diff --git a/lib/erl_docgen/src/erl_docgen.app.src b/lib/erl_docgen/src/erl_docgen.app.src
new file mode 100644
index 0000000000..1720464b6d
--- /dev/null
+++ b/lib/erl_docgen/src/erl_docgen.app.src
@@ -0,0 +1,12 @@
+{application, erl_docgen,
+ [{description, "Misc tools for building documentation"},
+ {vsn, "%VSN%"},
+ {modules, [otp_specs
+ ]
+ },
+ {registered,[]},
+ {applications, [kernel,stdlib]},
+ {env, []
+ }
+ ]
+}.
diff --git a/lib/erl_docgen/src/erl_docgen.appup.src b/lib/erl_docgen/src/erl_docgen.appup.src
new file mode 100644
index 0000000000..54a63833e6
--- /dev/null
+++ b/lib/erl_docgen/src/erl_docgen.appup.src
@@ -0,0 +1 @@
+{"%VSN%",[],[]}.
diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/otp_specs.erl
new file mode 100644
index 0000000000..728ddb2e6e
--- /dev/null
+++ b/lib/erl_docgen/src/otp_specs.erl
@@ -0,0 +1,701 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-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%
+%%
+
+-module(otp_specs).
+
+-export([module/2, package/2, overview/2, type/1]).
+
+-include("xmerl.hrl").
+
+-define(XML_EXPORT, xmerl_xml).
+-define(DEFAULT_XML_EXPORT, ?XML_EXPORT).
+-define(DEFAULT_PP, erl_pp).
+-define(IND(N), #xmlText{value="\n" ++ lists:duplicate(N, $\s)}).
+-define(NL, "\n").
+
+module(Element, Options) ->
+ XML = layout_module(Element, init_opts(Options)),
+ Export = proplists:get_value(xml_export, Options,
+ ?DEFAULT_XML_EXPORT),
+ xmerl:export_simple(XML, Export, [#xmlAttribute{name=prolog,
+ value=""}]).
+
+-record(opts, {pretty_print, file_suffix}).
+
+init_opts(Options) ->
+ #opts{pretty_print = proplists:get_value(pretty_print,
+ Options, ?DEFAULT_PP),
+ %% It *is* depending on edoc.hrl!
+ file_suffix = proplists:get_value(file_suffix, Options, ".html")}.
+
+layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
+ Name = get_attrval(name, E),
+ Functions = [{function_name(Elem), Elem} ||
+ Elem <- get_content(functions, Es)],
+ Types = [{type_name(Elem), Elem} || Elem <- get_content(typedecls, Es)],
+ Body = [{module,
+ [{name,[Name]}],
+ ([?NL] ++ types(lists:sort(Types), Opts)
+ ++ functions(lists:sort(Functions), Opts)
+ ++ timestamp())}],
+ Body.
+
+timestamp() ->
+ [{timestamp, [io_lib:fwrite("Generated by EDoc, ~s, ~s.",
+ [edoc_lib:datestr(date()),
+ edoc_lib:timestr(time())])]},?NL].
+
+functions(Fs, Opts) ->
+ lists:flatmap(fun ({Name, E}) -> function(Name, E, Opts) end, Fs).
+
+function(Name, #xmlElement{content = Es}, Opts) ->
+ TS = get_content(typespec, Es),
+ Spec = typespec(TS, Opts),
+ [{spec,(Name
+ ++ [?IND(2),{contract,Spec}]
+ ++ typespec_annos(TS))},
+ ?NL].
+
+function_name(E) ->
+ [] = get_attrval(module, E),
+ [?IND(2),{name,[atom(get_attrval(name, E))]},
+ ?IND(2),{arity,[get_attrval(arity, E)]}].
+
+label_anchor(Content, E) ->
+ case get_attrval(label, E) of
+ "" -> Content;
+ Ref -> [{marker, [{id, Ref}], Content}]
+ end.
+
+typespec([], _Opts) -> [];
+typespec(Es, Opts) ->
+ {Head, LDefs} = collect_clause(Es, Opts),
+ clause(Head, LDefs) ++ [?IND(2)].
+
+collect_clause(Es, Opts) ->
+ Name = t_name(get_elem(erlangName, Es)),
+ Defs = get_elem(localdef, Es),
+ [Type] = get_elem(type, Es),
+ {format_spec(Name, Type, Opts), collect_local_defs(Defs, Opts)}.
+
+clause(Head, LDefs) ->
+ FC = [?IND(6),{head,Head}] ++ local_clause_defs(LDefs),
+ [?IND(4),{clause,FC}].
+
+local_clause_defs([]) -> [];
+local_clause_defs(LDefs) ->
+ LocalDefs = [{subtype,T} || T <- coalesce_local_defs(LDefs, [])],
+ [?IND(6),{guard,margin(8, LocalDefs)}].
+
+types(Ts, Opts) ->
+ lists:flatmap(fun ({Name, E}) -> typedecl(Name, E, Opts) end, Ts).
+
+typedecl(Name, E=#xmlElement{content = Es}, Opts) ->
+ TD = get_content(typedef, Es),
+ TypeDef = typedef(E, TD, Opts),
+ [{type,(Name
+ ++ [?IND(2),{typedecl, TypeDef}]
+ ++ typedef_annos(TD))},
+ ?NL].
+
+type_name(#xmlElement{content = Es}) ->
+ Typedef = get_content(typedef, Es),
+ [E] = get_elem(erlangName, Typedef),
+ Args = get_content(argtypes, Typedef),
+ [] = get_attrval(module, E),
+ [?IND(2),{name,[atom(get_attrval(name, E))]},
+ ?IND(2),{n_vars,[integer_to_list(length(Args))]}].
+
+typedef(E, Es, Opts) ->
+ Ns = get_elem(erlangName, Es),
+ Name =
+ ([t_name(Ns), "("]
+ ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])),
+ LDefs = collect_local_defs(get_elem(localdef, Es), Opts),
+ TypeHead = case get_elem(type, Es) of
+ [] -> label_anchor(Name, E);
+ Type -> (label_anchor(Name, E)
+ ++ format_type(Name, Type, Opts))
+ end,
+ ([?IND(6),{typehead,TypeHead}]
+ ++ local_type_defs(LDefs, [])).
+
+local_type_defs([], _) -> [];
+local_type_defs(LDefs, Last) ->
+ LocalDefs = [{local_def,T} || T <- coalesce_local_defs(LDefs, Last)],
+ [?IND(6),{local_defs,margin(8, LocalDefs)}].
+
+collect_local_defs(Es, Opts) ->
+ [collect_localdef(E, Opts) || E <- Es].
+
+collect_localdef(E = #xmlElement{content = Es}, Opts) ->
+ Name = case get_elem(typevar, Es) of
+ [] ->
+ label_anchor(N0 = t_abstype(get_content(abstype, Es)), E);
+ [V] ->
+ N0 = t_var(V)
+ end,
+ {Name,N0,format_type(N0, get_elem(type, Es), Opts)}.
+
+%% "A = t(), B = t()" is coalesced into "A = B = t()".
+%% Names as B above are kept, but the formated string is empty.
+coalesce_local_defs([], _Last) ->
+ [];
+coalesce_local_defs([{Name,N0,TypeS} | L], Last) when Name =:= N0 ->
+ cld(L, [{Name,N0}], TypeS, Last);
+coalesce_local_defs([{Name,N0,TypeS} | L], Last) ->
+ [local_def(N0, Name, TypeS, Last, L) | coalesce_local_defs(L, Last)].
+
+cld([{Name,N0,TypeS} | L], Names, TypeS, Last) when Name =:= N0 ->
+ cld(L, [{Name,N0} | Names], TypeS, Last);
+cld(L, Names0, TypeS, Last) ->
+ Names = [{_,Name0} | Names1] = lists:reverse(Names0),
+ NS = join([N || {N,_} <- Names], [" = "]),
+ ([local_def(Name0, NS, TypeS, Last, L) |
+ [local_def(N0, "", "", [], L) || {_,N0} <- Names1]]
+ ++ coalesce_local_defs(L, Last)).
+
+local_def(Name, NS, TypeS, Last, L) ->
+ [{typename,Name},{string,NS ++ TypeS ++ [Last || L =:= []]}].
+
+%% join([], Sep) when is_list(Sep) ->
+%% [];
+join([H|T], Sep) ->
+ H ++ lists:append([Sep ++ X || X <- T]).
+
+%% Use the default formatting of EDoc, which creates references, and
+%% then insert newlines and indentation according to erl_pp (the
+%% (fast) Erlang pretty printer).
+format_spec(Name, Type, #opts{pretty_print = erl_pp}=Opts) ->
+ try
+ L = t_clause(Name, Type),
+ O = pp_clause(Name, Type),
+ {R, ".\n"} = diaf(L, O, Opts),
+ R
+ catch _:_ ->
+ %% Example: "@spec ... -> record(a)"
+ format_spec(Name, Type, Opts#opts{pretty_print=default})
+ end;
+format_spec(Sep, Type, _Opts) ->
+ t_clause(Sep, Type).
+
+t_clause(Name, Type) ->
+ #xmlElement{content = [#xmlElement{name = 'fun', content = C}]} = Type,
+ [Name] ++ t_fun(C).
+
+pp_clause(Pre, Type) ->
+ Types = ot_utype([Type]),
+ Atom = lists:duplicate(iolist_size(Pre), $a),
+ L1 = erl_pp:attribute({attribute,0,spec,{{list_to_atom(Atom),0},[Types]}}),
+ "-spec " ++ L2 = lists:flatten(L1),
+ L3 = Pre ++ lists:nthtail(length(Atom), L2),
+ re:replace(L3, "\n ", "\n", [{return,list},global]).
+
+format_type(Name, Type, #opts{pretty_print = erl_pp}=Opts) ->
+ try
+ L = t_utype(Type),
+ O = pp_type(Name, Type),
+ {R, ".\n"} = diaf(L, O, Opts),
+ [" = "] ++ R
+ catch _:_ ->
+ %% Example: "t() = record(a)."
+ format_type(Name, Type, Opts#opts{pretty_print=default})
+ end;
+format_type(_Name, Type, _Opts) ->
+ [" = "] ++ t_utype(Type).
+
+pp_type(Prefix, Type) ->
+ Atom = list_to_atom(lists:duplicate(iolist_size(Prefix), $a)),
+ L1 = erl_pp:attribute({attribute,0,type,{Atom,ot_utype(Type),[]}}),
+ {L2,N} = case lists:dropwhile(fun(C) -> C =/= $: end, lists:flatten(L1)) of
+ ":: " ++ L3 -> {L3,9}; % compensation for extra "()" and ":"
+ "::\n" ++ L3 -> {"\n"++L3,6}
+ end,
+ Ss = lists:duplicate(N, $\s),
+ re:replace(L2, "\n"++Ss, "\n", [{return,list},global]).
+
+diaf(L, O0, Opts) ->
+ {R0, O} = diaf(L, [], O0, [], Opts),
+ R1 = rewrite_some_predefs(lists:reverse(R0)),
+ R = indentation(lists:flatten(R1)),
+ {R, O}.
+
+diaf([C | L], St, [C | O], R, Opts) ->
+ diaf(L, St, O, [[C] | R], Opts);
+diaf(" "++L, St, O, R, Opts) ->
+ diaf(L, St, O, R, Opts);
+diaf("", [Cs | St], O, R, Opts) ->
+ diaf(Cs, St, O, R, Opts);
+diaf("", [], O, R, _Opts) ->
+ {R, O};
+diaf(L, St, " "++O, R, Opts) ->
+ diaf(L, St, O, [" " | R], Opts);
+diaf(L, St, "\n"++O, R, Opts) ->
+ Ss = lists:takewhile(fun(C) -> C =:= $\s end, O),
+ diaf(L, St, lists:nthtail(length(Ss), O), ["\n"++Ss | R], Opts);
+diaf([{seealso, HRef0, S0} | L], St, O0, R, Opts) ->
+ {S, O} = diaf(S0, app_fix(O0), Opts),
+ HRef = fix_mod_ref(HRef0, Opts),
+ diaf(L, St, O, [{seealso, HRef, S} | R], Opts);
+diaf("="++L, St, "::"++O, R, Opts) ->
+ %% EDoc uses "=" for record field types; Dialyzer uses "::". Maybe
+ %% there should be an option for this, possibly affecting other
+ %% similar discrepancies.
+ diaf(L, St, O, ["=" | R], Opts);
+diaf([Cs | L], St, O, R, Opts) ->
+ diaf(Cs, [L | St], O, R, Opts).
+
+rewrite_some_predefs(S) ->
+ xpredef(lists:flatten(S)).
+
+xpredef([]) ->
+ [];
+xpredef("neg_integer()"++L) ->
+ ["integer() =< -1"] ++ xpredef(L);
+xpredef("non_neg_integer()"++L) ->
+ ["integer() >= 0"] ++ xpredef(L);
+xpredef("pos_integer()"++L) ->
+ ["integer() >= 1"] ++ xpredef(L);
+xpredef([T | Es]) when is_tuple(T) ->
+ [T | xpredef(Es)];
+xpredef([E | Es]) ->
+ [[E] | xpredef(Es)].
+
+indentation([]) ->
+ [];
+indentation([$\n|L]) ->
+ [{br,[]}|indent(L)];
+indentation([T | Es]) when is_tuple(T) ->
+ [T | indentation(Es)];
+indentation([E|L]) ->
+ [[E]|indentation(L)].
+
+indent([$\s|L]) ->
+ [{nbsp,[]}|indent(L)];
+indent(L) ->
+ indentation(L).
+
+app_fix(L) ->
+ try
+ {"//" ++ R1,L2} = app_fix(L, 1),
+ [App, Mod] = string:tokens(R1, "/"),
+ "//" ++ atom(App) ++ "/" ++ atom(Mod) ++ L2
+ catch _:_ -> L
+ end.
+
+app_fix(L, I) -> % a bit slow
+ {L1, L2} = lists:split(I, L),
+ case erl_scan:tokens([], L1 ++ ". ", 1) of
+ {done, {ok,[{atom,_,Atom}|_],_}, _} -> {atom_to_list(Atom), L2};
+ _ -> app_fix(L, I+1)
+ end.
+
+%% Remove the file suffix from module references.
+fix_mod_ref(HRef, #opts{file_suffix = ""}) ->
+ HRef;
+fix_mod_ref([{marker, S}]=HRef0, #opts{file_suffix = FS}) ->
+ {A, B} = lists:splitwith(fun(C) -> C =/= $# end, S),
+ case lists:member($:, A) of
+ true ->
+ HRef0; % should "save" most application references "http:"
+ false ->
+ case {lists:suffix(FS, A), B} of
+ {true, "#"++_} ->
+ [{marker, lists:sublist(A, length(A)-length(FS)) ++ B}];
+ _ ->
+ HRef0
+ end
+ end.
+
+see(E, Es) ->
+ case href(E) of
+ [] -> Es;
+ Ref ->
+ [{seealso, Ref, Es}]
+ end.
+
+href(E) ->
+ case get_attrval(href, E) of
+ "" -> [];
+ URI ->
+ [{marker, URI}]
+ end.
+
+atom(String) ->
+ io_lib:write_atom(list_to_atom(String)).
+
+t_name([E]) ->
+ N = get_attrval(name, E),
+ case get_attrval(module, E) of
+ "" -> atom(N);
+ M ->
+ S = atom(M) ++ ":" ++ atom(N),
+ case get_attrval(app, E) of
+ "" -> S;
+ A -> "//" ++ atom(A) ++ "/" ++ S
+ end
+ end.
+
+t_utype([E]) ->
+ t_utype_elem(E).
+
+t_utype_elem(E=#xmlElement{content = Es}) ->
+ case get_attrval(name, E) of
+ "" -> t_type(Es);
+ Name ->
+ T = t_type(Es),
+ case T of
+ [Name] -> T; % avoid generating "Foo::Foo"
+ T -> [Name] ++ ["::"] ++ T
+ end
+ end.
+
+t_type([E=#xmlElement{name = typevar}]) ->
+ t_var(E);
+t_type([E=#xmlElement{name = atom}]) ->
+ t_atom(E);
+t_type([E=#xmlElement{name = integer}]) ->
+ t_integer(E);
+t_type([E=#xmlElement{name = range}]) ->
+ t_range(E);
+t_type([E=#xmlElement{name = binary}]) ->
+ t_binary(E);
+t_type([E=#xmlElement{name = float}]) ->
+ t_float(E);
+t_type([#xmlElement{name = nil}]) ->
+ t_nil();
+t_type([#xmlElement{name = list, content = Es}]) ->
+ t_list(Es);
+t_type([#xmlElement{name = nonempty_list, content = Es}]) ->
+ t_nonempty_list(Es);
+t_type([#xmlElement{name = tuple, content = Es}]) ->
+ t_tuple(Es);
+t_type([#xmlElement{name = 'fun', content = Es}]) ->
+ ["fun("] ++ t_fun(Es) ++ [")"];
+t_type([E = #xmlElement{name = record, content = Es}]) ->
+ t_record(E, Es);
+t_type([E = #xmlElement{name = abstype, content = Es}]) ->
+ t_abstype(E, Es);
+t_type([#xmlElement{name = union, content = Es}]) ->
+ t_union(Es).
+
+t_var(E) ->
+ [get_attrval(name, E)].
+
+t_atom(E) ->
+ [get_attrval(value, E)].
+
+t_integer(E) ->
+ [get_attrval(value, E)].
+
+t_range(E) ->
+ [get_attrval(value, E)].
+
+t_binary(E) ->
+ [get_attrval(value, E)].
+
+t_float(E) ->
+ [get_attrval(value, E)].
+
+t_nil() ->
+ ["[]"].
+
+t_list(Es) ->
+ ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"].
+
+t_nonempty_list(Es) ->
+ ["["] ++ t_utype(get_elem(type, Es)) ++ [", ...]"].
+
+t_tuple(Es) ->
+ ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]).
+
+t_fun(Es) ->
+ ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
+ [") -> "] ++ t_utype(get_elem(type, Es))).
+
+t_record(E, Es) ->
+ Name = ["#"] ++ t_type(get_elem(atom, Es)),
+ case get_elem(field, Es) of
+ [] ->
+ see(E, [Name, "{}"]);
+ Fs ->
+ see(E, Name) ++ ["{"] ++ seq(fun t_field/1, Fs, ["}"])
+ end.
+
+t_field(#xmlElement{content = Es}) ->
+ t_type(get_elem(atom, Es)) ++ [" = "] ++ t_utype(get_elem(type, Es)).
+
+t_abstype(E, Es) ->
+ Name = t_name(get_elem(erlangName, Es)),
+ case get_elem(type, Es) of
+ [] ->
+ see(E, [Name, "()"]);
+ Ts ->
+ see(E, [Name]) ++ ["("] ++ seq(fun t_utype_elem/1, Ts, [")"])
+ end.
+
+t_abstype(Es) ->
+ ([t_name(get_elem(erlangName, Es)), "("]
+ ++ seq(fun t_utype_elem/1, get_elem(type, Es), [")"])).
+
+t_union(Es) ->
+ seq(fun t_utype_elem/1, Es, " | ", []).
+
+seq(F, Es, Tail) ->
+ seq(F, Es, ", ", Tail).
+
+seq(F, [E], _Sep, Tail) ->
+ F(E) ++ Tail;
+seq(F, [E | Es], Sep, Tail) ->
+ F(E) ++ [Sep] ++ seq(F, Es, Sep, Tail);
+seq(_F, [], _Sep, Tail) ->
+ Tail.
+
+get_elem(Name, [#xmlElement{name = Name} = E | Es]) ->
+ [E | get_elem(Name, Es)];
+get_elem(Name, [_ | Es]) ->
+ get_elem(Name, Es);
+get_elem(_, []) ->
+ [].
+
+get_attr(Name, [#xmlAttribute{name = Name} = A | As]) ->
+ [A | get_attr(Name, As)];
+get_attr(Name, [_ | As]) ->
+ get_attr(Name, As);
+get_attr(_, []) ->
+ [].
+
+get_attrval(Name, #xmlElement{attributes = As}) ->
+ case get_attr(Name, As) of
+ [#xmlAttribute{value = V}] ->
+ V;
+ [] -> ""
+ end.
+
+get_content(Name, Es) ->
+ case get_elem(Name, Es) of
+ [#xmlElement{content = Es1}] ->
+ Es1;
+ [] -> []
+ end.
+
+overview(_, _Options) -> [].
+
+package(_, _Options) -> [].
+
+type(_) -> [].
+
+%% ---------------------------------------------------------------------
+
+ot_utype([E]) ->
+ ot_utype_elem(E).
+
+ot_utype_elem(E=#xmlElement{content = Es}) ->
+ case get_attrval(name, E) of
+ "" -> ot_type(Es);
+ N ->
+ Name = {var,0,list_to_atom(N)},
+ T = ot_type(Es),
+ case T of
+ Name -> T;
+ T -> {ann_type,0,[Name, T]}
+ end
+ end.
+
+ot_type([E=#xmlElement{name = typevar}]) ->
+ ot_var(E);
+ot_type([E=#xmlElement{name = atom}]) ->
+ ot_atom(E);
+ot_type([E=#xmlElement{name = integer}]) ->
+ ot_integer(E);
+ot_type([E=#xmlElement{name = range}]) ->
+ ot_range(E);
+ot_type([E=#xmlElement{name = binary}]) ->
+ ot_binary(E);
+ot_type([E=#xmlElement{name = float}]) ->
+ ot_float(E);
+ot_type([#xmlElement{name = nil}]) ->
+ ot_nil();
+ot_type([#xmlElement{name = list, content = Es}]) ->
+ ot_list(Es);
+ot_type([#xmlElement{name = nonempty_list, content = Es}]) ->
+ ot_nonempty_list(Es);
+ot_type([#xmlElement{name = tuple, content = Es}]) ->
+ ot_tuple(Es);
+ot_type([#xmlElement{name = 'fun', content = Es}]) ->
+ ot_fun(Es);
+ot_type([#xmlElement{name = record, content = Es}]) ->
+ ot_record(Es);
+ot_type([#xmlElement{name = abstype, content = Es}]) ->
+ ot_abstype(Es);
+ot_type([#xmlElement{name = union, content = Es}]) ->
+ ot_union(Es).
+
+ot_var(E) ->
+ {var,0,list_to_atom(get_attrval(name, E))}.
+
+ot_atom(E) ->
+ {ok, [Atom], _} = erl_scan:string(get_attrval(value, E), 0),
+ Atom.
+
+ot_integer(E) ->
+ {integer,0,list_to_integer(get_attrval(value, E))}.
+
+ot_range(E) ->
+ [I1, I2] = string:tokens(get_attrval(value, E), "."),
+ {type,0,range,[{integer,0,list_to_integer(I1)},
+ {integer,0,list_to_integer(I2)}]}.
+
+ot_binary(E) ->
+ {Base, Unit} =
+ case string:tokens(get_attrval(value, E), ",:*><") of
+ [] ->
+ {0, 0};
+ ["_",B] ->
+ {list_to_integer(B), 0};
+ ["_","_",U] ->
+ {0, list_to_integer(U)};
+ ["_",B,_,"_",U] ->
+ {list_to_integer(B), list_to_integer(U)}
+ end,
+ {type,0,binary,[{integer,0,Base},{integer,0,Unit}]}.
+
+ot_float(E) ->
+ {float,0,list_to_float(get_attrval(value, E))}.
+
+ot_nil() ->
+ {nil,0}.
+
+ot_list(Es) ->
+ {type,0,list,[ot_utype(get_elem(type, Es))]}.
+
+ot_nonempty_list(Es) ->
+ {type,0,nonempty_list,[ot_utype(get_elem(type, Es))]}.
+
+ot_tuple(Es) ->
+ {type,0,tuple,[ot_utype_elem(E) || E <- Es]}.
+
+ot_fun(Es) ->
+ Range = ot_utype(get_elem(type, Es)),
+ Args = [ot_utype_elem(A) || A <- get_content(argtypes, Es)],
+ {type,0,'fun',[{type,0,product,Args},Range]}.
+
+ot_record(Es) ->
+ {type,0,record,[ot_type(get_elem(atom, Es)) |
+ [ot_field(F) || F <- get_elem(field, Es)]]}.
+
+ot_field(#xmlElement{content = Es}) ->
+ {type,0,field_type,
+ [ot_type(get_elem(atom, Es)), ot_utype(get_elem(type, Es))]}.
+
+ot_abstype(Es) ->
+ ot_name(get_elem(erlangName, Es),
+ [ot_utype_elem(Elem) || Elem <- get_elem(type, Es)]).
+
+ot_union(Es) ->
+ {type,0,union,[ot_utype_elem(E) || E <- Es]}.
+
+ot_name(Es, T) ->
+ case ot_name(Es) of
+ [Mod, ":", Atom] ->
+ {remote_type,0,[{atom,0,list_to_atom(Mod)},
+ {atom,0,list_to_atom(Atom)},T]};
+ "tuple" when T =:= [] ->
+ {type,0,tuple,any};
+ Atom ->
+ {type,0,list_to_atom(Atom),T}
+ end.
+
+ot_name([E]) ->
+ Atom = get_attrval(name, E),
+ case get_attrval(module, E) of
+ "" -> Atom;
+ M ->
+ case get_attrval(app, E) of
+ "" ->
+ [M, ":", Atom];
+ A ->
+ ["//"++A++"/" ++ M, ":", Atom] % EDoc only!
+ end
+ end.
+
+%% Returns exactly those annotations that can be referred to. Note
+%% that a Dialyzer type/spec (currently) can have more annotations
+%% than can be represented by EDoc types. Note also that edoc_dia
+%% has annotated all type variables with themselves.
+typespec_annos([]) -> [?NL];
+typespec_annos([_|Es]) ->
+ annotations(clause_annos(Es)).
+
+clause_annos(Es) ->
+ [annos(get_elem(type, Es)), local_defs_annos(get_elem(localdef, Es))].
+
+typedef_annos(Es) ->
+ annotations([(case get_elem(type, Es) of
+ [] -> [];
+ T -> annos(T)
+ end
+ ++ lists:flatmap(fun annos_elem/1,
+ get_content(argtypes, Es))),
+ local_defs_annos(get_elem(localdef, Es))]).
+
+local_defs_annos(Es) ->
+ lists:flatmap(fun localdef_annos/1, Es).
+
+localdef_annos(#xmlElement{content = Es}) ->
+ annos(get_elem(type, Es)).
+
+annotations(AnnoL) ->
+ Annos = lists:usort(lists:flatten(AnnoL)),
+ margin(2, Annos).
+
+margin(N, L) ->
+ lists:append([[?IND(N),E] || E <- L]) ++ [?IND(N-2)].
+
+annos([E]) ->
+ annos_elem(E).
+
+annos_elem(E=#xmlElement{content = Es}) ->
+ case get_attrval(name, E) of
+ "" -> annos_type(Es);
+ "..." -> annos_type(Es); % compensate for a kludge in edoc_dia.erl
+ N ->
+ [{anno,[N]} | annos_type(Es)]
+ end.
+
+annos_type([#xmlElement{name = list, content = Es}]) ->
+ annos(get_elem(type, Es));
+annos_type([#xmlElement{name = nonempty_list, content = Es}]) ->
+ annos(get_elem(type, Es));
+annos_type([#xmlElement{name = tuple, content = Es}]) ->
+ lists:flatmap(fun annos_elem/1, Es);
+annos_type([#xmlElement{name = 'fun', content = Es}]) ->
+ (annos(get_elem(type, Es))
+ ++ lists:flatmap(fun annos_elem/1, get_content(argtypes, Es)));
+annos_type([#xmlElement{name = record, content = Es}]) ->
+ lists:append([annos(get_elem(type, Es1)) ||
+ #xmlElement{content = Es1} <- get_elem(field, Es)]);
+annos_type([#xmlElement{name = abstype, content = Es}]) ->
+ lists:flatmap(fun annos_elem/1, get_elem(type, Es));
+annos_type([#xmlElement{name = union, content = Es}]) ->
+ lists:flatmap(fun annos_elem/1, Es);
+annos_type([E=#xmlElement{name = typevar}]) ->
+ annos_elem(E);
+annos_type(_) ->
+ [].
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index 5084c65230..a6c2f64dd0 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -511,29 +511,28 @@ static int erl_term_len_helper(ETERM *ep, int dist)
case ERL_INTEGER:
i = ep->uval.ival.i;
- if ((i > ERL_MAX) || (i < ERL_MIN)) len = 7;
- else if ((i < 256) && (i >= 0)) len = 2;
+ if ((i < 256) && (i >= 0)) len = 2;
else len = 5;
break;
case ERL_U_INTEGER:
u = ep->uval.uival.u;
- if (u > ERL_MAX) len = 7;
+ if ((int)u < 0) len = 7;
else if (u < 256) len = 2;
else len = 5;
break;
case ERL_LONGLONG:
l = ep->uval.llval.i;
- if ((l > ((long long) ERL_MAX)) ||
- (l < ((long long) ERL_MIN))) len = 11;
+ if ((l > ((long long) INT_MAX)) ||
+ (l < ((long long) INT_MIN))) len = 11;
else if ((l < 256) && (l >= 0)) len = 2;
else len = 5;
break;
case ERL_U_LONGLONG:
ul = ep->uval.ullval.u;
- if (ul > ((unsigned long long) ERL_MAX)) len = 11;
+ if (ul > ((unsigned long long) INT_MAX)) len = 11;
else if (ul < 256) len = 2;
else len = 5;
break;
@@ -546,12 +545,7 @@ static int erl_term_len_helper(ETERM *ep, int dist)
case ERL_REF:
i = strlen((char *)ERL_REF_NODE(ep));
- if (dist >= 4 && ERL_REF_LEN(ep) > 1) {
- len = 1 + 2 + (i+3) + 1 + ERL_REF_LEN(ep) * 4;
- } else {
- /* 1 + N + 4 + 1 where N = 3 + strlen */
- len = 9 + i;
- }
+ len = 1 + 2 + (i+3) + 1 + ERL_REF_LEN(ep) * 4;
break;
case ERL_PORT:
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index 09a37409f2..524a04a3b4 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -232,7 +232,7 @@ send_integers(P) ->
?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
- case erlang:system_info(wordsize) of
+ case erlang:system_info({wordsize,external}) of
4 ->
?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
index f273efd532..80d7f69520 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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
@@ -98,14 +98,30 @@ static void encode_decode(ETERM* original, const char* text)
{
static unsigned char encoded[16*1024];
ETERM* new_terms;
- int bytes = erl_encode(original, encoded);
+ ETERM* head;
+ int bytes;
+ int len;
+
+ /* If a list, check the elements one by one first */
+ head = erl_hd(original);
+ if (head != NULL) {
+ encode_decode(head, "CAR");
+ encode_decode(erl_tl(original), "CDR");
+ }
+ bytes = erl_encode(original, encoded);
if (bytes == 0) {
fail("failed to encode terms");
}
else if (bytes > sizeof(encoded)) {
fail("encoded terms buffer overflow");
}
+ else if (bytes != (len=erl_term_len(original))) {
+ fprintf(stderr, "bytes(%d) != len(%d) for term ", bytes, len);
+ erl_print_term(stderr, original);
+ fprintf(stderr, " [%s]\r\n", text);
+ fail("erl_encode and erl_term_len do not agree");
+ }
else if ((new_terms = erl_decode(encoded)) == NULL) {
fail("failed to decode terms");
}
diff --git a/lib/et/src/et_selector.erl b/lib/et/src/et_selector.erl
index f39f21aa70..c8e9c907b2 100644
--- a/lib/et/src/et_selector.erl
+++ b/lib/et/src/et_selector.erl
@@ -115,13 +115,13 @@ change_pattern({Mod, Pattern}) when is_atom(Mod) ->
old_ctp({Mod, _Fun, Args}) ->
case Mod of
- et -> ignore;
+ et -> {ok, ignore};
_ -> dbg:ctp({Mod, report_event, Args})
end.
old_tp({Mod, _Fun, Args}, Pattern) ->
case Mod of
- et -> ignore;
+ et -> {ok, ignore};
_ -> dbg:tp({Mod, report_event, Args}, Pattern)
end.
diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile
index 19be96d763..2cdc579275 100644
--- a/lib/eunit/doc/src/Makefile
+++ b/lib/eunit/doc/src/Makefile
@@ -146,7 +146,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
rm -f $(MAN3DIR)/*
- rm -f $(XML_CHAPTER_FILES) *.html
+ rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index 59084a52fb..4a86a108cf 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -16,7 +16,7 @@
%% $Id: eunit.erl 339 2009-04-05 14:10:47Z rcarlsson $
%%
%% @copyright 2004-2009 Micka�l R�mond, Richard Carlsson
-%% @author Micka�l R�mond <[email protected]>
+%% @author Micka&euml;l R&eacute;mond <[email protected]>
%% [http://www.process-one.net/]
%% @author Richard Carlsson <[email protected]>
%% [http://user.it.uu.se/~richardc/]
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index aeda31d251..eb994a990a 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -15,7 +15,7 @@
%%
%% $Id: $
%%
-%% @author Micka�l R�mond <[email protected]>
+%% @author Micka&euml;l R&eacute;mond <[email protected]>
%% @copyright 2009 Micka�l R�mond, Paul Guyot
%% @see eunit
%% @doc Surefire reports for EUnit (Format used by Maven and Atlassian
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 696414eb7a..1cba89c621 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -4678,16 +4678,16 @@ t_HttpRequest() ->
t_tuple([t_atom('http_request'), t_HttpMethod(), t_HttpUri(), t_HttpVersion()]).
t_HttpResponse() ->
- t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_string()]).
+ t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_HttpString()]).
t_HttpHeader() ->
- t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_string()]).
+ t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_HttpString()]).
t_HttpError() ->
- t_tuple([t_atom('http_error'), t_string()]).
+ t_tuple([t_atom('http_error'), t_HttpString()]).
t_HttpMethod() ->
- t_sup(t_HttpMethodAtom(), t_string()).
+ t_sup(t_HttpMethodAtom(), t_HttpString()).
t_HttpMethodAtom() ->
t_atoms(['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE']).
@@ -4696,18 +4696,18 @@ t_HttpUri() ->
t_sup([t_atom('*'),
t_tuple([t_atom('absoluteURI'),
t_sup(t_atom('http'), t_atom('https')),
- t_string(),
+ t_HttpString(),
t_sup(t_non_neg_integer(), t_atom('undefined')),
- t_string()]),
- t_tuple([t_atom('scheme'), t_string(), t_string()]),
- t_tuple([t_atom('abs_path'), t_string()]),
- t_string()]).
+ t_HttpString()]),
+ t_tuple([t_atom('scheme'), t_HttpString(), t_HttpString()]),
+ t_tuple([t_atom('abs_path'), t_HttpString()]),
+ t_HttpString()]).
t_HttpVersion() ->
t_tuple([t_non_neg_integer(), t_non_neg_integer()]).
t_HttpField() ->
- t_sup(t_HttpFieldAtom(), t_string()).
+ t_sup(t_HttpFieldAtom(), t_HttpString()).
t_HttpFieldAtom() ->
t_atoms(['Cache-Control', 'Connection', 'Date', 'Pragma', 'Transfer-Encoding',
@@ -4724,6 +4724,9 @@ t_HttpFieldAtom() ->
'Set-Cookie', 'Set-Cookie2', 'X-Forwarded-For', 'Cookie',
'Keep-Alive', 'Proxy-Connection']).
+t_HttpString() ->
+ t_sup(t_string(),t_binary()).
+
%% =====================================================================
%% These are used for the built-in functions of 'code'
%% =====================================================================
diff --git a/lib/inets/doc/src/ftp.xml b/lib/inets/doc/src/ftp.xml
index 25dfe716fc..ca902d8d9d 100644
--- a/lib/inets/doc/src/ftp.xml
+++ b/lib/inets/doc/src/ftp.xml
@@ -107,7 +107,7 @@
<tag>{mode, Mode}</tag>
<item>
<marker id="mode"></marker>
- <p>Mode = <c>active | passive</c> </p>>
+ <p>Mode = <c>active | passive</c> </p>
<p>Default is <c>passive</c>. </p>
</item>
diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml
index ea8053cafa..672ea3fa98 100644
--- a/lib/inets/doc/src/http_client.xml
+++ b/lib/inets/doc/src/http_client.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>
@@ -57,7 +57,7 @@
[{inets, [{services, [{httpc, PropertyList}]}]}]
</pre>
<p>For valid properties see
- <seealso marker="http">httpc(3)</seealso>. </p>
+ <seealso marker="httpc">httpc(3)</seealso>. </p>
</section>
<section>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 9c8df28fec..c20358178b 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.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>
@@ -172,7 +172,8 @@ ssl_options() = {verify, code()} |
{autoredirect, boolean()} |
{proxy_auth, {userstring(), passwordstring()}} |
{version, http_version()} |
- {relaxed, boolean()}</v>
+ {relaxed, boolean()} |
+ {url_encode, boolean()}</v>
<v>timeout() = integer() >= 0 | infinity</v>
<v>Options = options()</v>
<v>options() = [option()]</v>
@@ -276,6 +277,11 @@ ssl_options() = {verify, code()} |
<p>Defaults to <c>false</c>. </p>
</item>
+ <tag><c><![CDATA[url_encode]]></c></tag>
+ <item>
+ <p>Will apply Percent-encoding, also known as URL encoding on the URL.</p>
+ <p>Defaults to <c>false</c>. </p>
+ </item>
</taglist>
<p>Option (<c>option()</c>) details: </p>
@@ -342,7 +348,7 @@ ssl_options() = {verify, code()} |
<p>Socket options to be used for this and subsequent
request(s). </p>
<p>Overrides any value set by the
- <seealso marker="set_options">set_options</seealso>
+ <seealso marker="#set_options">set_options</seealso>
function. </p>
<p>Note that the validity of the options are <em>not</em>
checked in any way. </p>
@@ -632,4 +638,3 @@ apply(Module, Function, [ReplyInfo | Args])
</section>
</erlref>
-
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 847605fe93..62f4e18f82 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.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>
@@ -421,7 +421,7 @@ bytes
Beware of trailing space in Replacement that will be used.
If you must have a space in Re use e.g the character encoding
- <code>\040</code> see <seealso marker="re">re(3)</seealso>.
+ <code>\040</code> see <seealso marker="stdlib:re">re(3)</seealso>.
</item>
<tag>{directory_index, [string()]}</tag>
@@ -931,6 +931,10 @@ bytes
connection
}).
</code>
+
+ <p>To acess the record in your callback-module use </p>
+ <code> -include_lib("inets/include/httpd.hrl"). </code>
+
<p>The fields of the <c>mod</c> record has the following meaning:
</p>
<taglist>
@@ -978,10 +982,10 @@ bytes
<c>parsed_header</c> contains all HTTP header fields from the
HTTP-request stored in a list as key-value tuples. See RFC 2616
for a listing of all header fields. For example the date field
- would be stored as: <c>{"date","Wed, 15 Oct 1997 14:35:17 GMT"}.
+ would be stored as: <c>{"date","Wed, 15 Oct 1997 14:35:17 GMT"} </c>.
RFC 2616 defines that HTTP is a case insensitive protocol and
the header fields may be in lower case or upper case. Httpd will
- ensure that all header field names are in lower case. </c>.
+ ensure that all header field names are in lower case.
</item>
<tag><c>entity_body</c></tag>
<item>The <c>Entity-Body</c> as defined
diff --git a/lib/inets/include/httpd.hrl b/lib/inets/include/httpd.hrl
new file mode 100644
index 0000000000..a7e63ca670
--- /dev/null
+++ b/lib/inets/include/httpd.hrl
@@ -0,0 +1,41 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+%%
+
+-ifndef(httpd_hrl).
+-define(httpd_hrl, true).
+
+-include_lib("kernel/include/file.hrl").
+
+-record(init_data,{peername,resolve}).
+
+-record(mod,{init_data,
+ data=[],
+ socket_type=ip_comm,
+ socket,
+ config_db,
+ method,
+ absolute_uri=[],
+ request_uri,
+ http_version,
+ request_line,
+ parsed_header=[],
+ entity_body,
+ connection}).
+-endif. % -ifdef(httpd_hrl).
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index 575c6efaec..0397b48ab2 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -51,7 +51,6 @@ MODULES = \
httpc_profile_sup \
httpc_response \
httpc_request \
- http_uri \
HRL_FILES = httpc_internal.hrl
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 851364001c..ae754fab94 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -442,18 +442,23 @@ handle_request(Method, Url,
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
+ UrlEncodeBool = HTTPOptions#http_options.url_encode,
+ MaybeEscPath = url_encode(Path, UrlEncodeBool),
+ MaybeEscQuery = url_encode(Query, UrlEncodeBool),
+ AbsUri = url_encode(Url, UrlEncodeBool),
+
Request = #request{from = Receiver,
scheme = Scheme,
address = {Host, Port},
- path = Path,
- pquery = Query,
+ path = MaybeEscPath,
+ pquery = MaybeEscQuery,
method = Method,
headers = HeadersRecord,
content = {ContentType, Body},
settings = HTTPOptions,
- abs_uri = Url,
+ abs_uri = AbsUri,
userinfo = UserInfo,
- stream = Stream,
+ stream = Stream,
headers_as_is = headers_as_is(Headers, Options),
socket_opts = SocketOpts,
started = Started},
@@ -471,6 +476,10 @@ handle_request(Method, Url,
Error
end.
+url_encode(URI, true) ->
+ http_uri:encode(URI);
+url_encode(URI, false) ->
+ URI.
handle_answer(RequestId, false, _) ->
{ok, RequestId};
@@ -578,12 +587,8 @@ http_options_default() ->
(_) ->
error
end,
- AutoRedirectPost = fun(Value) when (Value =:= true) orelse
- (Value =:= false) ->
- {ok, Value};
- (_) ->
- error
- end,
+ AutoRedirectPost = boolfun(),
+
SslPost = fun(Value) when is_list(Value) ->
{ok, {?HTTP_DEFAULT_SSL_KIND, Value}};
({ssl, SslOptions}) when is_list(SslOptions) ->
@@ -601,12 +606,8 @@ http_options_default() ->
(_) ->
error
end,
- RelaxedPost = fun(Value) when (Value =:= true) orelse
- (Value =:= false) ->
- {ok, Value};
- (_) ->
- error
- end,
+ RelaxedPost = boolfun(),
+
ConnTimeoutPost =
fun(Value) when is_integer(Value) andalso (Value >= 0) ->
{ok, Value};
@@ -615,6 +616,8 @@ http_options_default() ->
(_) ->
error
end,
+
+ UrlDecodePost = boolfun(),
[
{version, {value, "HTTP/1.1"}, #http_options.version, VersionPost},
{timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost},
@@ -622,18 +625,21 @@ http_options_default() ->
{ssl, {value, {?HTTP_DEFAULT_SSL_KIND, []}}, #http_options.ssl, SslPost},
{proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost},
{relaxed, {value, false}, #http_options.relaxed, RelaxedPost},
+ {url_encode, {value, false}, #http_options.url_encode, UrlDecodePost},
%% this field has to be *after* the timeout option (as that field is used for the default value)
{connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost}
].
+boolfun() ->
+ fun(Value) when (Value =:= true) orelse
+ (Value =:= false) ->
+ {ok, Value};
+ (_) ->
+ error
+ end.
request_options_defaults() ->
- VerifyBoolean =
- fun(Value) when ((Value =:= true) orelse (Value =:= false)) ->
- ok;
- (_) ->
- error
- end,
+ VerifyBoolean = boolfun(),
VerifySync = VerifyBoolean,
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 8af6613fa2..cb6f3e2841 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -713,33 +713,38 @@ terminate(normal,
profile_name = ProfileName,
request = Request,
timers = Timers,
- pipeline = Pipeline}) ->
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
?hcrt("terminate(normal) - remote close",
[{id, Id}, {profile, ProfileName}]),
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
%% Cancel timers
- #timers{request_timers = ReqTmrs, queue_timer = QTmr} = Timers,
- cancel_timer(QTmr, timeout_queue),
- lists:foreach(fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
- ReqTmrs),
+ cancel_timers(Timers),
%% Maybe deliver answers to requests
- deliver_answers([Request | queue:to_list(Pipeline)]),
+ deliver_answer(Request),
%% And, just in case, close our side (**really** overkill)
http_transport:close(SocketType, Socket);
-terminate(_, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
+terminate(Reason, #state{session = #session{id = Id,
+ socket = Socket,
+ socket_type = SocketType},
request = undefined,
profile_name = ProfileName,
timers = Timers,
pipeline = Pipeline,
keep_alive = KeepAlive} = State) ->
+ ?hcrt("terminate",
+ [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
+
+ %% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
maybe_retry_queue(Pipeline, State),
@@ -772,59 +777,55 @@ maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
maybe_send_answer(Request, Answer, State) ->
answer_request(Request, Answer, State).
-deliver_answers([]) ->
- ?hcrd("deliver answer done", []),
- ok;
-deliver_answers([#request{id = Id, from = From} = Request | Requests])
+deliver_answer(#request{id = Id, from = From} = Request)
when is_pid(From) ->
Response = httpc_response:error(Request, socket_closed_remotely),
?hcrd("deliver answer", [{id, Id}, {from, From}, {response, Response}]),
- httpc_response:send(From, Response),
- deliver_answers(Requests);
-deliver_answers([Request|Requests]) ->
+ httpc_response:send(From, Response);
+deliver_answer(Request) ->
?hcrd("skip deliver answer", [{request, Request}]),
- deliver_answers(Requests).
+ ok.
%%--------------------------------------------------------------------
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-code_change(_, #state{request = Request, pipeline = Queue} = State,
- [{from, '5.0.1'}, {to, '5.0.2'}]) ->
- Settings = new_http_options(Request#request.settings),
- NewRequest = Request#request{settings = Settings},
- NewQueue = new_queue(Queue, fun new_http_options/1),
- {ok, State#state{request = NewRequest, pipeline = NewQueue}};
-
-code_change(_, #state{request = Request, pipeline = Queue} = State,
- [{from, '5.0.2'}, {to, '5.0.1'}]) ->
- Settings = old_http_options(Request#request.settings),
- NewRequest = Request#request{settings = Settings},
- NewQueue = new_queue(Queue, fun old_http_options/1),
- {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+%% code_change(_, #state{request = Request, pipeline = Queue} = State,
+%% [{from, '5.0.1'}, {to, '5.0.2'}]) ->
+%% Settings = new_http_options(Request#request.settings),
+%% NewRequest = Request#request{settings = Settings},
+%% NewQueue = new_queue(Queue, fun new_http_options/1),
+%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+
+%% code_change(_, #state{request = Request, pipeline = Queue} = State,
+%% [{from, '5.0.2'}, {to, '5.0.1'}]) ->
+%% Settings = old_http_options(Request#request.settings),
+%% NewRequest = Request#request{settings = Settings},
+%% NewQueue = new_queue(Queue, fun old_http_options/1),
+%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
code_change(_, State, _) ->
{ok, State}.
-new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
- Auth, Relaxed}) ->
- {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
- Auth, Relaxed}.
-
-old_http_options({http_options, _, TimeOut, AutoRedirect,
- SslOpts, Auth, Relaxed}) ->
- {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
-
-new_queue(Queue, Fun) ->
- List = queue:to_list(Queue),
- NewList =
- lists:map(fun(Request) ->
- Settings =
- Fun(Request#request.settings),
- Request#request{settings = Settings}
- end, List),
- queue:from_list(NewList).
+%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
+%% Auth, Relaxed}) ->
+%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
+%% Auth, Relaxed}.
+
+%% old_http_options({http_options, _, TimeOut, AutoRedirect,
+%% SslOpts, Auth, Relaxed}) ->
+%% {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
+
+%% new_queue(Queue, Fun) ->
+%% List = queue:to_list(Queue),
+%% NewList =
+%% lists:map(fun(Request) ->
+%% Settings =
+%% Fun(Request#request.settings),
+%% Request#request{settings = Settings}
+%% end, List),
+%% queue:from_list(NewList).
%%%--------------------------------------------------------------------
@@ -854,12 +855,18 @@ connect(SocketType, ToAddress,
inet6fb4 ->
Opts3 = [inet6 | Opts2],
case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
- {error, Reason} when ((Reason =:= nxdomain) orelse
- (Reason =:= eafnosupport)) ->
+ {error, _Reason} = Error ->
Opts4 = [inet | Opts2],
- http_transport:connect(SocketType, ToAddress, Opts4, Timeout);
- Other ->
- Other
+ case http_transport:connect(SocketType,
+ ToAddress, Opts4, Timeout) of
+ {error, _} ->
+ %% Reply with the "original" error
+ Error;
+ OK ->
+ OK
+ end;
+ OK ->
+ OK
end;
_ ->
Opts3 = [IpFamily | Opts2],
@@ -1440,6 +1447,12 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
timers =
Timers#timers{request_timers =
lists:delete(Timer, RequestTimers)}}.
+
+cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
+ cancel_timer(QTmr, timeout_queue),
+ CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
+ lists:foreach(CancelTimer, ReqTmrs).
+
cancel_timer(undefined, _) ->
ok;
cancel_timer(Timer, TimeoutMsg) ->
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 3cdd95a02b..1d8a5b6a92 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -60,7 +60,11 @@
relaxed = false,
%% integer() - ms before a connect times out
- connect_timeout = ?HTTP_REQUEST_CTIMEOUT
+ connect_timeout = ?HTTP_REQUEST_CTIMEOUT,
+
+ %% bool() - Use %-encoding rfc 2396
+ url_encode
+
}
).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 1e1bde220b..591cb78c29 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -734,10 +734,11 @@ handle_connect_and_send(_StarterPid, ReqId, HandlerPid, Result,
ok;
[] ->
- error_report(Profile,
- "handler (~p) successfully started "
- "for unknown request ~p => canceling",
- [HandlerPid, ReqId]),
+ ?hcri("handler successfully started "
+ "for unknown request => canceling",
+ [{profile, Profile},
+ {handler, HandlerPid},
+ {request, ReqId}]),
httpc_handler:cancel(ReqId, HandlerPid)
end.
diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile
index 5dac3b0c00..aaf3cfb995 100644
--- a/lib/inets/src/http_lib/Makefile
+++ b/lib/inets/src/http_lib/Makefile
@@ -45,7 +45,8 @@ MODULES = \
http_transport\
http_util \
http_request \
- http_response
+ http_response \
+ http_uri
HRL_FILES = http_internal.hrl
diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl
index b8121852b8..0024d19fc1 100644
--- a/lib/inets/src/http_lib/http_transport.erl
+++ b/lib/inets/src/http_lib/http_transport.erl
@@ -192,24 +192,31 @@ listen_ip_comm(Addr, Port) ->
case IpFamily of
inet6fb4 ->
Opts2 = [inet6 | Opts],
+ ?hlrt("try ipv6 listen", [{port, NewPort}, {opts, Opts2}]),
case (catch gen_tcp:listen(NewPort, Opts2)) of
{error, Reason} when ((Reason =:= nxdomain) orelse
(Reason =:= eafnosupport)) ->
Opts3 = [inet | Opts],
+ ?hlrt("ipv6 listen failed - try ipv4 instead",
+ [{reason, Reason}, {port, NewPort}, {opts, Opts3}]),
gen_tcp:listen(NewPort, Opts3);
%% This is when a given hostname has resolved to a
%% IPv4-address. The inet6-option together with a
%% {ip, IPv4} option results in badarg
- {'EXIT', _} ->
+ {'EXIT', Reason} ->
Opts3 = [inet | Opts],
+ ?hlrt("ipv6 listen exit - try ipv4 instead",
+ [{reason, Reason}, {port, NewPort}, {opts, Opts3}]),
gen_tcp:listen(NewPort, Opts3);
Other ->
+ ?hlrt("ipv6 listen done", [{other, Other}]),
Other
end;
_ ->
Opts2 = [IpFamily | Opts],
+ ?hlrt("listen", [{port, NewPort}, {opts, Opts2}]),
gen_tcp:listen(NewPort, Opts2)
end.
diff --git a/lib/inets/src/http_client/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index 615a0d8ec4..44b9face0b 100644
--- a/lib/inets/src/http_client/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -1,26 +1,26 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-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%
%%
%%
-module(http_uri).
--export([parse/1]).
+-export([parse/1, encode/1, decode/1]).
%%%=========================================================================
%%% API
@@ -34,10 +34,25 @@ parse(AbsURI) ->
{UserInfo, Host, Port, Path, Query} ->
{Scheme, UserInfo, Host, Port, Path, Query};
_ ->
- {error, {malformed_url, AbsURI}}
+ {error, {malformed_url, AbsURI}}
end
end.
+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([]) ->
+ [].
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
@@ -56,7 +71,7 @@ parse_scheme(AbsURI) ->
parse_uri_rest(Scheme, "//" ++ URIPart) ->
- {Authority, PathQuery} =
+ {Authority, PathQuery} =
case split_uri(URIPart, "/", URIPart, 1, 0) of
Split = {_, _} ->
Split;
@@ -68,7 +83,7 @@ parse_uri_rest(Scheme, "//" ++ URIPart) ->
{URIPart,""}
end
end,
-
+
{UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1),
{Host, Port} = parse_host_port(Scheme, HostPort),
{Path, Query} = parse_path_query(PathQuery),
@@ -78,7 +93,6 @@ parse_uri_rest(Scheme, "//" ++ URIPart) ->
parse_path_query(PathQuery) ->
{Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0),
{path(Path), Query}.
-
parse_host_port(Scheme,"[" ++ HostPort) -> %ipv6
DefaultPort = default_port(Scheme),
@@ -90,12 +104,12 @@ parse_host_port(Scheme, HostPort) ->
DefaultPort = default_port(Scheme),
{Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1),
{Host, int_port(Port)}.
-
+
split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
case inets_regexp:first_match(UriPart, SplitChar) of
{match, Match, _} ->
{string:substr(UriPart, 1, Match - SkipLeft),
- string:substr(UriPart, Match + SkipRight, length(UriPart))};
+ string:substr(UriPart, Match + SkipRight, length(UriPart))};
nomatch ->
NoMatchResult
end.
@@ -114,3 +128,15 @@ path("") ->
"/";
path(Path) ->
Path.
+
+uri_encode(Char, Reserved) ->
+ case sets:is_element(Char, Reserved) of
+ true ->
+ [ $% | http_util:integer_to_hexlist(Char)];
+ false ->
+ [Char]
+ end.
+
+hex2dec(X) when (X>=$0) andalso (X=<$9) -> X-$0;
+hex2dec(X) when (X>=$A) andalso (X=<$F) -> X-$A+10;
+hex2dec(X) when (X>=$a) andalso (X=<$f) -> X-$a+10.
diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile
index 879e605217..bdd8c5ee3c 100644
--- a/lib/inets/src/http_server/Makefile
+++ b/lib/inets/src/http_server/Makefile
@@ -82,7 +82,9 @@ MODULES = \
mod_security \
mod_security_server
-HRL_FILES = httpd.hrl httpd_internal.hrl mod_auth.hrl
+INCLUDE = ../../include
+
+HRL_FILES = $(INCLUDE)/httpd.hrl httpd_internal.hrl mod_auth.hrl
ERL_FILES = $(MODULES:%=%.erl)
@@ -98,9 +100,9 @@ include ../inets_app/inets.mk
ERL_COMPILE_FLAGS += \
$(INETS_FLAGS) \
$(INETS_ERL_COMPILE_FLAGS) \
- -I../../include \
+ -I$(INCLUDE) \
-I../inets_app \
- -I../http_lib
+ -I../http_lib \
# ----------------------------------------------------
diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
index fb5fa1c758..93608dbf96 100644
--- a/lib/inets/src/http_server/httpd.erl
+++ b/lib/inets/src/http_server/httpd.erl
@@ -24,7 +24,6 @@
-include("httpd.hrl").
-
%% Behavior callbacks
-export([
start_standalone/1,
@@ -271,8 +270,8 @@ foreach([KeyValue|Rest]) ->
{ok, Plus2Space, _} = inets_regexp:gsub(KeyValue,"[\+]"," "),
case inets_regexp:split(Plus2Space,"=") of
{ok,[Key|Value]} ->
- [{httpd_util:decode_hex(Key),
- httpd_util:decode_hex(lists:flatten(Value))}|foreach(Rest)];
+ [{http_uri:decode(Key),
+ http_uri:decode(lists:flatten(Value))}|foreach(Rest)];
{ok,_} ->
foreach(Rest)
end.
diff --git a/lib/inets/src/http_server/httpd.hrl b/lib/inets/src/http_server/httpd.hrl
deleted file mode 100644
index 0db8a029bb..0000000000
--- a/lib/inets/src/http_server/httpd.hrl
+++ /dev/null
@@ -1,82 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-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%
-%%
-%%
-
--include_lib("kernel/include/file.hrl").
-
--ifndef(SERVER_SOFTWARE).
--define(SERVER_SOFTWARE,"inets/develop"). % Define in Makefile!
--endif.
--define(SERVER_PROTOCOL,"HTTP/1.1").
--define(DEFAULT_MODS, [mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi,
- mod_dir, mod_get, mod_head, mod_log, mod_disk_log]).
--define(SOCKET_CHUNK_SIZE,8192).
--define(SOCKET_MAX_POLL,25).
--define(FILE_CHUNK_SIZE,64*1024).
--define(GATEWAY_INTERFACE,"CGI/1.1").
--define(NICE(Reason),lists:flatten(atom_to_list(?MODULE)++": "++Reason)).
--define(DEFAULT_CONTEXT,
- [{errmsg,"[an error occurred while processing this directive]"},
- {timefmt,"%A, %d-%b-%y %T %Z"},
- {sizefmt,"abbrev"}]).
-
-
--ifdef(inets_error).
--define(ERROR(Format, Args), io:format("E(~p:~p:~p) : "++Format++"~n",
- [self(),?MODULE,?LINE]++Args)).
--else.
--define(ERROR(F,A),[]).
--endif.
-
--ifdef(inets_log).
--define(LOG(Format, Args), io:format("L(~p:~p:~p) : "++Format++"~n",
- [self(),?MODULE,?LINE]++Args)).
--else.
--define(LOG(F,A),[]).
--endif.
-
--ifdef(inets_debug).
--define(DEBUG(Format, Args), io:format("D(~p:~p:~p) : "++Format++"~n",
- [self(),?MODULE,?LINE]++Args)).
--else.
--define(DEBUG(F,A),[]).
--endif.
-
--ifdef(inets_cdebug).
--define(CDEBUG(Format, Args), io:format("C(~p:~p:~p) : "++Format++"~n",
- [self(),?MODULE,?LINE]++Args)).
--else.
--define(CDEBUG(F,A),[]).
--endif.
-
-
--record(init_data,{peername,resolve}).
--record(mod,{init_data,
- data=[],
- socket_type=ip_comm,
- socket,
- config_db,
- method,
- absolute_uri=[],
- request_uri,
- http_version,
- request_line,
- parsed_header=[],
- entity_body,
- connection}).
diff --git a/lib/inets/src/http_server/httpd_acceptor.erl b/lib/inets/src/http_server/httpd_acceptor.erl
index c261eff6b2..bcebb6a9e3 100644
--- a/lib/inets/src/http_server/httpd_acceptor.erl
+++ b/lib/inets/src/http_server/httpd_acceptor.erl
@@ -21,6 +21,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
%% Internal application API
-export([start_link/5, start_link/6]).
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 8438c4037e..f4d8a6c09f 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -31,8 +31,8 @@
validate_properties/1]).
-define(VMODULE,"CONF").
--include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("httpd.hrl").
-include_lib("inets/src/http_lib/http_internal.hrl").
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index 5fd529100e..7e21d9e158 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -22,11 +22,13 @@
-export([handle_error/4]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
+
handle_error(eacces, Op, ModData, Path) ->
- handle_error(403, Op, ModData, Path,"");
+ handle_error(403, Op, ModData, Path,"Forbidden");
handle_error(enoent, Op, ModData, Path) ->
- handle_error(404, Op, ModData, Path,"");
+ handle_error(404, Op, ModData, Path,"File not found");
handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
@@ -34,8 +36,8 @@ handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": To 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(500, Op, none, Path, "").
+handle_error(_Reason, Op, ModData, Path) ->
+ handle_error(404, Op, ModData, Path, "File not found").
handle_error(StatusCode, Op, none, Path, Reason) ->
{StatusCode, none, ?NICE("Can't " ++ Op ++ Path ++ Reason)};
diff --git a/lib/inets/src/http_server/httpd_internal.hrl b/lib/inets/src/http_server/httpd_internal.hrl
index 38b0ddefd3..108469ea0a 100644
--- a/lib/inets/src/http_server/httpd_internal.hrl
+++ b/lib/inets/src/http_server/httpd_internal.hrl
@@ -21,7 +21,50 @@
-ifndef(httpd_internal_hrl).
-define(httpd_internal_hrl, true).
--include_lib("inets/src/inets_app/inets_internal.hrl").
+-ifndef(SERVER_SOFTWARE).
+-define(SERVER_SOFTWARE,"inets/develop"). % Define in Makefile!
+-endif.
+-define(SERVER_PROTOCOL,"HTTP/1.1").
+-define(DEFAULT_MODS, [mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi,
+ mod_dir, mod_get, mod_head, mod_log, mod_disk_log]).
+-define(SOCKET_CHUNK_SIZE,8192).
+-define(SOCKET_MAX_POLL,25).
+-define(FILE_CHUNK_SIZE,64*1024).
+-define(GATEWAY_INTERFACE,"CGI/1.1").
+-define(NICE(Reason),lists:flatten(atom_to_list(?MODULE)++": "++Reason)).
+-define(DEFAULT_CONTEXT,
+ [{errmsg,"[an error occurred while processing this directive]"},
+ {timefmt,"%A, %d-%b-%y %T %Z"},
+ {sizefmt,"abbrev"}]).
+
+
+-ifdef(inets_error).
+-define(ERROR(Format, Args), io:format("E(~p:~p:~p) : "++Format++"~n",
+ [self(),?MODULE,?LINE]++Args)).
+-else.
+-define(ERROR(F,A),[]).
+-endif.
+
+-ifdef(inets_log).
+-define(LOG(Format, Args), io:format("L(~p:~p:~p) : "++Format++"~n",
+ [self(),?MODULE,?LINE]++Args)).
+-else.
+-define(LOG(F,A),[]).
+-endif.
+
+-ifdef(inets_debug).
+-define(DEBUG(Format, Args), io:format("D(~p:~p:~p) : "++Format++"~n",
+ [self(),?MODULE,?LINE]++Args)).
+-else.
+-define(DEBUG(F,A),[]).
+-endif.
+
+-ifdef(inets_cdebug).
+-define(CDEBUG(Format, Args), io:format("C(~p:~p:~p) : "++Format++"~n",
+ [self(),?MODULE,?LINE]++Args)).
+-else.
+-define(CDEBUG(F,A),[]).
+-endif.
-define(SERVICE, httpd).
-define(hdri(Label, Content), ?report_important(Label, ?SERVICE, Content)).
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 883acbf585..7084d9824a 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -304,9 +304,9 @@ validate_uri(RequestURI) ->
UriNoQueryNoHex =
case string:str(RequestURI, "?") of
0 ->
- (catch httpd_util:decode_hex(RequestURI));
+ (catch http_uri:decode(RequestURI));
Ndx ->
- (catch httpd_util:decode_hex(string:left(RequestURI, Ndx)))
+ (catch http_uri:decode(string:left(RequestURI, Ndx)))
end,
case UriNoQueryNoHex of
{'EXIT',_Reason} ->
diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl
index a742cbef76..d3115150b0 100644
--- a/lib/inets/src/http_server/httpd_script_env.erl
+++ b/lib/inets/src/http_server/httpd_script_env.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -23,6 +23,7 @@
-export([create_env/3]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
%%%=========================================================================
%%% Internal application API
diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl
index 1507c6852a..f94e5459c1 100644
--- a/lib/inets/src/http_server/httpd_sup.erl
+++ b/lib/inets/src/http_server/httpd_sup.erl
@@ -37,7 +37,7 @@
-define(TIMEOUT, 15000).
-include("httpd_internal.hrl").
-
+-include("inets_internal.hrl").
%%%=========================================================================
%%% API
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index cfad79638f..789f12652b 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -21,7 +21,7 @@
-export([ip_address/2, lookup/2, lookup/3, multi_lookup/2,
lookup_mime/2, lookup_mime/3, lookup_mime_default/2,
lookup_mime_default/3, reason_phrase/1, message/3, rfc1123_date/0,
- rfc1123_date/1, day/1, month/1, decode_hex/1,
+ rfc1123_date/1, day/1, month/1,
flatlength/1, split_path/1, split_script_path/1,
suffix/1, split/3, uniq/1,
make_name/2,make_name/3,make_name/4,strip/1,
@@ -32,7 +32,7 @@
dir_validate/2, file_validate/2, mime_type_validate/1,
mime_types_validate/1, custom_date/0]).
--export([encode_hex/1]).
+-export([encode_hex/1, decode_hex/1]).
-include_lib("kernel/include/file.hrl").
ip_address({_,_,_,_} = Address, _IpFamily) ->
@@ -175,13 +175,13 @@ reason_phrase(_) -> "Internal Server Error".
%% message
message(301,URL,_) ->
- "The document has moved <A HREF=\""++URL++"\">here</A>.";
+ "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. "++Msg;
+ "Your browser sent a query that this server could not understand. "++ maybe_encode(Msg);
message(401,none,_) ->
"This server could not verify that you
are authorized to access the document you
@@ -190,9 +190,9 @@ 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 "++RequestURI++" on this server.";
+ "You don't have permission to access "++ maybe_encode(RequestURI) ++" on this server.";
message(404,RequestURI,_) ->
- "The requested URL "++RequestURI++" was not found on this server.";
+ "The requested URL " ++ maybe_encode(RequestURI) ++ " was not found on this server.";
message(408, Timeout, _) ->
Timeout;
message(412,none,_) ->
@@ -200,7 +200,7 @@ message(412,none,_) ->
message(413, Reason,_) ->
"Entity: " ++ Reason;
message(414,ReasonPhrase,_) ->
- "Message "++ReasonPhrase++".";
+ "Message "++ ReasonPhrase ++".";
message(416,ReasonPhrase,_) ->
ReasonPhrase;
@@ -216,15 +216,23 @@ message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
if
is_atom(Method) ->
atom_to_list(Method)++
- " to "++RequestURI++" ("++HTTPVersion++") not supported.";
+ " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported.";
is_list(Method) ->
Method++
- " to "++RequestURI++" ("++HTTPVersion++") not supported."
+ " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported."
end;
message(503, String, _ConfigDB) ->
"This service in unavailable due to: "++String.
+maybe_encode(URI) ->
+ case lists:member($%, URI) of
+ true ->
+ URI;
+ false ->
+ http_uri:encode(URI)
+ end.
+
%%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}}
convert_request_date([D,A,Y,DateType| Rest])->
@@ -381,16 +389,11 @@ month(12) -> "Dec".
%% decode_hex
-decode_hex([$%,Hex1,Hex2|Rest]) ->
- [hex2dec(Hex1)*16+hex2dec(Hex2)|decode_hex(Rest)];
-decode_hex([First|Rest]) ->
- [First|decode_hex(Rest)];
-decode_hex([]) ->
- [].
+decode_hex(URI) ->
+ http_uri:decode(URI).
-hex2dec(X) when (X>=$0) andalso (X=<$9) -> X-$0;
-hex2dec(X) when (X>=$A) andalso (X=<$F) -> X-$A+10;
-hex2dec(X) when (X>=$a) andalso (X=<$f) -> X-$a+10.
+encode_hex(URI) ->
+ http_uri:encode(URI).
%% flatlength
flatlength(List) ->
@@ -411,7 +414,7 @@ split_path(Path) ->
case inets_regexp:match(Path,"[\?].*\$") of
%% A QUERY_STRING exists!
{match,Start,Length} ->
- {httpd_util:decode_hex(string:substr(Path,1,Start-1)),
+ {http_uri:decode(string:substr(Path,1,Start-1)),
string:substr(Path,Start,Length)};
%% A possible PATH_INFO exists!
nomatch ->
@@ -419,9 +422,9 @@ split_path(Path) ->
end.
split_path([],SoFar) ->
- {httpd_util:decode_hex(lists:reverse(SoFar)),[]};
+ {http_uri:decode(lists:reverse(SoFar)),[]};
split_path([$/|Rest],SoFar) ->
- Path=httpd_util:decode_hex(lists:reverse(SoFar)),
+ Path=http_uri:decode(lists:reverse(SoFar)),
case file:read_file_info(Path) of
{ok,FileInfo} when FileInfo#file_info.type =:= regular ->
{Path,[$/|Rest]};
@@ -454,7 +457,7 @@ pathinfo_querystring([C|Rest], SoFar) ->
pathinfo_querystring(Rest, [C|SoFar]).
split_script_path([$?|QueryString], SoFar) ->
- Path = httpd_util:decode_hex(lists:reverse(SoFar)),
+ Path = http_uri:decode(lists:reverse(SoFar)),
case file:read_file_info(Path) of
{ok,FileInfo} when FileInfo#file_info.type =:= regular ->
{Path, [$?|QueryString]};
@@ -464,7 +467,7 @@ split_script_path([$?|QueryString], SoFar) ->
not_a_script
end;
split_script_path([], SoFar) ->
- Path = httpd_util:decode_hex(lists:reverse(SoFar)),
+ Path = http_uri:decode(lists:reverse(SoFar)),
case file:read_file_info(Path) of
{ok,FileInfo} when FileInfo#file_info.type =:= regular ->
{Path, []};
@@ -474,7 +477,7 @@ split_script_path([], SoFar) ->
not_a_script
end;
split_script_path([$/|Rest], SoFar) ->
- Path = httpd_util:decode_hex(lists:reverse(SoFar)),
+ Path = http_uri:decode(lists:reverse(SoFar)),
case file:read_file_info(Path) of
{ok, FileInfo} when FileInfo#file_info.type =:= regular ->
{Path, [$/|Rest]};
@@ -608,9 +611,6 @@ hexlist_to_integer(List)->
%%----------------------------------------------------------------------
%%Converts an integer to an hexlist
%%----------------------------------------------------------------------
-encode_hex(Num)->
- integer_to_hexlist(Num).
-
integer_to_hexlist(Num) when is_integer(Num) ->
http_util:integer_to_hexlist(Num).
@@ -735,7 +735,6 @@ valid_accept_timeout(A) ->
valid_config(_) ->
ok.
-
%%----------------------------------------------------------------------
%% Enable debugging,
%%----------------------------------------------------------------------
diff --git a/lib/inets/src/http_server/mod_actions.erl b/lib/inets/src/http_server/mod_actions.erl
index d50ed4b16c..c3946ff9b4 100644
--- a/lib/inets/src/http_server/mod_actions.erl
+++ b/lib/inets/src/http_server/mod_actions.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -21,6 +21,7 @@
-export([do/1,load/2, store/2]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
%% do
diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl
index 9c5a8cc1c6..0b9fe4cfe0 100644
--- a/lib/inets/src/http_server/mod_alias.erl
+++ b/lib/inets/src/http_server/mod_alias.erl
@@ -29,6 +29,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-define(VMODULE,"ALIAS").
diff --git a/lib/inets/src/http_server/mod_auth.erl b/lib/inets/src/http_server/mod_auth.erl
index 07cafb4726..85a87ab884 100644
--- a/lib/inets/src/http_server/mod_auth.erl
+++ b/lib/inets/src/http_server/mod_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -38,6 +38,7 @@
-include("httpd.hrl").
-include("mod_auth.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-define(VMODULE,"AUTH").
diff --git a/lib/inets/src/http_server/mod_auth_dets.erl b/lib/inets/src/http_server/mod_auth_dets.erl
index bc6c2b70a0..a48725d5d9 100644
--- a/lib/inets/src/http_server/mod_auth_dets.erl
+++ b/lib/inets/src/http_server/mod_auth_dets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -35,6 +35,7 @@
-export([store_directory_data/3]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
-include("mod_auth.hrl").
store_directory_data(_Directory, DirData, Server_root) ->
diff --git a/lib/inets/src/http_server/mod_auth_plain.erl b/lib/inets/src/http_server/mod_auth_plain.erl
index d88859d28a..c0a83711ba 100644
--- a/lib/inets/src/http_server/mod_auth_plain.erl
+++ b/lib/inets/src/http_server/mod_auth_plain.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -22,6 +22,8 @@
-include("httpd.hrl").
-include("mod_auth.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
+
-define(VMODULE,"AUTH_PLAIN").
diff --git a/lib/inets/src/http_server/mod_auth_server.erl b/lib/inets/src/http_server/mod_auth_server.erl
index 5f9e59be9d..947273bd9e 100644
--- a/lib/inets/src/http_server/mod_auth_server.erl
+++ b/lib/inets/src/http_server/mod_auth_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -22,6 +22,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-behaviour(gen_server).
diff --git a/lib/inets/src/http_server/mod_cgi.erl b/lib/inets/src/http_server/mod_cgi.erl
index 33605b9698..c854166c29 100644
--- a/lib/inets/src/http_server/mod_cgi.erl
+++ b/lib/inets/src/http_server/mod_cgi.erl
@@ -27,6 +27,7 @@
-export([do/1, load/2, store/2]).
-include("http_internal.hrl").
+-include("httpd_internal.hrl").
-include("httpd.hrl").
-define(VMODULE,"CGI").
diff --git a/lib/inets/src/http_server/mod_dir.erl b/lib/inets/src/http_server/mod_dir.erl
index cdc7cc01e4..d791ee28e9 100644
--- a/lib/inets/src/http_server/mod_dir.erl
+++ b/lib/inets/src/http_server/mod_dir.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -18,9 +18,11 @@
%%
%%
-module(mod_dir).
--export([do/1]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
+
+-export([do/1]).
%% do
@@ -57,7 +59,7 @@ do_dir(Info) ->
case file:read_file_info(DefaultPath) of
{ok,FileInfo} when FileInfo#file_info.type == directory ->
DecodedRequestURI =
- httpd_util:decode_hex(Info#mod.request_uri),
+ http_uri:decode(Info#mod.request_uri),
?DEBUG("do_dir -> ~n"
" Path: ~p~n"
" DefaultPath: ~p~n"
diff --git a/lib/inets/src/http_server/mod_disk_log.erl b/lib/inets/src/http_server/mod_disk_log.erl
index 95e0d00c70..5a3766de66 100644
--- a/lib/inets/src/http_server/mod_disk_log.erl
+++ b/lib/inets/src/http_server/mod_disk_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -28,7 +28,7 @@
-define(VMODULE,"DISK_LOG").
-include("httpd.hrl").
-
+-include("httpd_internal.hrl").
%%%=========================================================================
%%% API
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index f7877aa9e2..929185a67a 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -30,6 +30,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-define(VMODULE,"ESI").
-define(DEFAULT_ERL_TIMEOUT,15000).
diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl
index 9fd1fcec47..5cb30e3d97 100644
--- a/lib/inets/src/http_server/mod_get.erl
+++ b/lib/inets/src/http_server/mod_get.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -20,7 +20,7 @@
-module(mod_get).
-export([do/1]).
-include("httpd.hrl").
-
+-include("httpd_internal.hrl").
%% do
do(Info) ->
diff --git a/lib/inets/src/http_server/mod_head.erl b/lib/inets/src/http_server/mod_head.erl
index 8b08d61651..c346fd4d23 100644
--- a/lib/inets/src/http_server/mod_head.erl
+++ b/lib/inets/src/http_server/mod_head.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
diff --git a/lib/inets/src/http_server/mod_htaccess.erl b/lib/inets/src/http_server/mod_htaccess.erl
index d8835198f5..e1f66d01c8 100644
--- a/lib/inets/src/http_server/mod_htaccess.erl
+++ b/lib/inets/src/http_server/mod_htaccess.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -23,6 +23,7 @@
-export([do/1, load/2, store/2]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Public methods that interface the eswapi %%
diff --git a/lib/inets/src/http_server/mod_include.erl b/lib/inets/src/http_server/mod_include.erl
index 534eba8a36..35f45bdd33 100644
--- a/lib/inets/src/http_server/mod_include.erl
+++ b/lib/inets/src/http_server/mod_include.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -21,6 +21,7 @@
-export([do/1,parse/2,config/6,include/6,echo/6,fsize/6,flastmod/6,exec/6]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
-define(VMODULE,"INCLUDE").
@@ -186,9 +187,9 @@ document_uri(ConfigDB, RequestURI) ->
FileName = string:substr(Path,Start,Length),
case inets_regexp:match(VirtualPath, FileName++"\$") of
{match, _, _} ->
- httpd_util:decode_hex(VirtualPath)++AfterPath;
+ http_uri:decode(VirtualPath)++AfterPath;
nomatch ->
- string:strip(httpd_util:decode_hex(VirtualPath),right,$/)++
+ string:strip(http_uri:decode(VirtualPath),right,$/)++
"/"++FileName++AfterPath
end.
diff --git a/lib/inets/src/http_server/mod_log.erl b/lib/inets/src/http_server/mod_log.erl
index de24d5a569..c8a2ec0dc4 100644
--- a/lib/inets/src/http_server/mod_log.erl
+++ b/lib/inets/src/http_server/mod_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -26,6 +26,7 @@
-export([do/1, load/2, store/2, remove/1]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
-define(VMODULE,"LOG").
%%%=========================================================================
diff --git a/lib/inets/src/http_server/mod_range.erl b/lib/inets/src/http_server/mod_range.erl
index 0698fb9099..a0408cba79 100644
--- a/lib/inets/src/http_server/mod_range.erl
+++ b/lib/inets/src/http_server/mod_range.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -20,7 +20,7 @@
-module(mod_range).
-export([do/1]).
-include("httpd.hrl").
-
+-include("httpd_internal.hrl").
%% do
do(Info) ->
diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl
index 79e2e1bdba..5d5b60cdbd 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-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -22,6 +22,7 @@
-export([do/1]).
-include("httpd.hrl").
+-include("httpd_internal.hrl").
do(Info) ->
?DEBUG("do -> response_control",[]),
diff --git a/lib/inets/src/http_server/mod_security.erl b/lib/inets/src/http_server/mod_security.erl
index 95793e1cfb..41988732ad 100644
--- a/lib/inets/src/http_server/mod_security.erl
+++ b/lib/inets/src/http_server/mod_security.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -32,6 +32,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-define(VMODULE,"SEC").
diff --git a/lib/inets/src/http_server/mod_security_server.erl b/lib/inets/src/http_server/mod_security_server.erl
index 58060686b3..784b3eba70 100644
--- a/lib/inets/src/http_server/mod_security_server.erl
+++ b/lib/inets/src/http_server/mod_security_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -45,6 +45,7 @@
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
-behaviour(gen_server).
diff --git a/lib/inets/src/http_server/mod_trace.erl b/lib/inets/src/http_server/mod_trace.erl
index df482228d8..7233925783 100644
--- a/lib/inets/src/http_server/mod_trace.erl
+++ b/lib/inets/src/http_server/mod_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 84d8c9278d..0194c65db9 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.5",
+ [
+ {restart_application, inets}
+ ]
+ },
{"5.4",
[
{restart_application, inets}
@@ -29,6 +34,11 @@
[
{restart_application, inets}
]
+ },
+ {"5.4",
+ [
+ {restart_application, inets}
+ ]
}
]
}.
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index bb7f2186af..0492d33eab 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -288,16 +288,20 @@ release_spec: opt
$(INSTALL_DATA) $(INETS_FILES) $(RELSYSDIR)/test
@for d in $(DATADIRS); do \
echo "installing data dir $$d"; \
- echo $$d/TAR.exclude2 > $$d/TAR.exclude2; \
- cat $$d/TAR.exclude >> $$d/TAR.exclude2; \
- find $$d -name '*.contrib*' >> $$d/TAR.exclude2; \
- find $$d -name '*.keep*' >> $$d/TAR.exclude2; \
- find $$d -name '*.mkelem*' >> $$d/TAR.exclude2; \
- find $$d -name '*~' >> $$d/TAR.exclude2; \
- find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \
- find $$d -name 'core' >> $$d/TAR.exclude2; \
- find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \
- tar cfX - $$d/TAR.exclude2 $$d | (cd $(RELSYSDIR)/test; tar xf -); \
+ if test -f $$d/TAR.exclude; then \
+ echo $$d/TAR.exclude2 > $$d/TAR.exclude2; \
+ cat $$d/TAR.exclude >> $$d/TAR.exclude2; \
+ find $$d -name '*.contrib*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.keep*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.mkelem*' >> $$d/TAR.exclude2; \
+ find $$d -name '*~' >> $$d/TAR.exclude2; \
+ find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \
+ find $$d -name 'core' >> $$d/TAR.exclude2; \
+ find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \
+ tar cfX - $$d/TAR.exclude2 $$d | (cd $(RELSYSDIR)/test; tar xf -); \
+ else \
+ tar cf - $$d | (cd $(RELSYSDIR)/test; tar xf -); \
+ fi; \
done
release_tests_spec: opt
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 902e440c80..94d5a48ef6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -254,9 +254,14 @@ init_per_testcase(Case, Timeout, Config) ->
[{watchdog, Dog}, {local_server, Server} | TmpConfig2]
end,
+ %% httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT},
+ %% ["localhost", ?IPV6_LOCAL_HOST]}}]),
+
httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT},
- ["localhost", ?IPV6_LOCAL_HOST]}}]),
- %% snmp:set_trace([gen_tcp, inet_tcp, prim_inet]),
+ ["localhost", ?IPV6_LOCAL_HOST]}},
+ {ipfamily, inet6fb4}]),
+
+ %% snmp:set_trace([gen_tcp]),
NewConfig.
@@ -471,7 +476,7 @@ http_relaxed(Config) when is_list(Config) ->
DummyServerPid ! stop,
ok = httpc:set_options([{ipv6, enabled}]),
- %% ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ %% ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -489,7 +494,7 @@ http_dummy_pipe(Config) when is_list(Config) ->
test_pipeline(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
http_inets_pipe(doc) ->
@@ -851,7 +856,7 @@ http_headers_dummy(Config) when is_list(Config) ->
], "text/plain", FooBar},
[], []),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -875,7 +880,7 @@ http_bad_response(Config) when is_list(Config) ->
test_server:format("Wrong Statusline: ~p~n", [Reason]),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1157,7 +1162,7 @@ http_redirect(Config) when is_list(Config) ->
tsp("http_redirect -> stop dummy server"),
DummyServerPid ! stop,
tsp("http_redirect -> reset ipfamily option (to inet6fb4)"),
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
tsp("http_redirect -> done"),
ok;
@@ -1181,7 +1186,7 @@ http_redirect_loop(Config) when is_list(Config) ->
{ok, {{_,300,_}, [_ | _], _}}
= httpc:request(get, {URL, []}, [], []),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
%%-------------------------------------------------------------------------
@@ -1215,7 +1220,7 @@ http_internal_server_error(Config) when is_list(Config) ->
ets:delete(unavailable),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1242,7 +1247,7 @@ http_userinfo(Config) when is_list(Config) ->
httpc:request(get, {URLUnAuth, []}, [], []),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1271,9 +1276,9 @@ http_cookie(Config) when is_list(Config) ->
ets:delete(cookie),
- ok = httpc:set_options([{cookies, disabled}, {ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{cookies, disabled}]),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
%%-------------------------------------------------------------------------
@@ -1643,7 +1648,7 @@ http_stream_once(Config) when is_list(Config) ->
p("http_stream_once -> stop dummy server", []),
DummyServerPid ! stop,
p("http_stream_once -> set ipfamily to inet6fb4", []),
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
p("http_stream_once -> done", []),
ok.
@@ -1847,7 +1852,7 @@ http_invalid_http(Config) when is_list(Config) ->
test_server:format("Parse error: ~p ~n", [Reason]),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1901,7 +1906,7 @@ transfer_encoding_otp_6807(Config) when is_list(Config) ->
"/capital_transfer_encoding.html",
{ok, {{_,200,_}, [_|_], [_ | _]}} = httpc:request(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1933,7 +1938,7 @@ empty_response_header_otp_6830(Config) when is_list(Config) ->
URL = ?URL_START ++ integer_to_list(Port) ++ "/no_headers.html",
{ok, {{_,200,_}, [], [_ | _]}} = httpc:request(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1950,7 +1955,7 @@ no_content_204_otp_6982(Config) when is_list(Config) ->
URL = ?URL_START ++ integer_to_list(Port) ++ "/no_content.html",
{ok, {{_,204,_}, [], []}} = httpc:request(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1968,7 +1973,7 @@ missing_CR_otp_7304(Config) when is_list(Config) ->
URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_CR.html",
{ok, {{_,200,_}, _, [_ | _]}} = httpc:request(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
@@ -1990,7 +1995,7 @@ otp_7883_1(Config) when is_list(Config) ->
{error, socket_closed_remotely} = httpc:request(URL),
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
otp_7883_2(doc) ->
@@ -2017,7 +2022,7 @@ otp_7883_2(Config) when is_list(Config) ->
end,
DummyServerPid ! stop,
- ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 *************
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
ok.
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index f86c1fcb49..9ba2e73942 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -1,7 +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
@@ -25,13 +25,16 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
+-define(URL_START, "http://localhost:").
+
all(doc) ->
["Basic test of httpd."];
all(suite) ->
[
uri_too_long_414,
- header_too_long_413
+ header_too_long_413,
+ escaped_url_in_error_body
].
%%--------------------------------------------------------------------
@@ -131,6 +134,31 @@ 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) ->
+ 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, Body}} = httpc:request(get, {URL, []},
+ [{url_encode, true}],
+ [{version, "HTTP/1.0"}, {full_result, false}]),
+ EscapedPath = find_URL_path(string:tokens(Body, " ")),
+ {ok, {404, Body1}} = httpc:request(get, {URL, []}, [],
+ [{version, "HTTP/1.0"}, {full_result, false}]),
+ EscapedPath = find_URL_path(string:tokens(Body1, " ")),
+ inets:stop(httpd, Pid).
-
-
+find_URL_path([]) ->
+ "";
+find_URL_path(["URL", URL | _]) ->
+ URL;
+find_URL_path([_ | Rest]) ->
+ find_URL_path(Rest).
diff --git a/lib/inets/test/inets_appup_test.erl b/lib/inets/test/inets_appup_test.erl
index d580c6c4c5..2c9c687c91 100644
--- a/lib/inets/test/inets_appup_test.erl
+++ b/lib/inets/test/inets_appup_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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
@@ -18,11 +18,12 @@
%%
%%
%%----------------------------------------------------------------------
-%% Purpose: Verify the application specifics of the Megaco application
+%% Purpose: Verify the application specifics of the Inets application
%%----------------------------------------------------------------------
-module(inets_appup_test).
-compile(export_all).
+-compile({no_auto_import,[error/1]}).
-include("inets_test_lib.hrl").
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 5eff9e4e3f..f462290a99 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -1,5 +1,24 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-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%
+
APPLICATION = inets
-INETS_VSN = 5.5
+INETS_VSN = 5.5.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index 17dd02acd4..885eeb2b0f 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
-module(error_handler).
+%% FIXME: remove no_native directive after HiPE has been changed to make
+%% remote calls link to the target's Export* like BEAM does.
+%% For a detailed explanation see the commit titled
+%% "error_handler: add no_native compiler directive"
+-compile(no_native).
%% A simple error handler.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index c9437df258..6f846ebc56 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -19,7 +19,7 @@
-module(code_SUITE).
-include("test_server.hrl").
-
+%-compile(export_all).
-export([all/1]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
@@ -31,6 +31,7 @@
where_is_file_cached/1, where_is_file_no_cache/1,
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
code_archive/1, code_archive2/1, on_load/1,
+ big_boot_embedded/1,
on_load_embedded/1, on_load_errors/1, native_early_modules/1]).
-export([init_per_testcase/2, fin_per_testcase/2,
@@ -53,6 +54,7 @@ all(suite) ->
where_is_file_no_cache, where_is_file_cached,
purge_stacktrace, mult_lib_roots, bad_erl_libs,
code_archive, code_archive2, on_load, on_load_embedded,
+ big_boot_embedded,
on_load_errors, native_early_modules].
init_per_suite(Config) ->
@@ -584,13 +586,21 @@ clash(Config) when is_list(Config) ->
TmpEzFile = Priv++"foobar-0.tmp.ez",
?line {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile),
?line true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"),
- ?line ok = file:delete(TmpEzFile),
+ case os:type() of
+ {win32,_} ->
+ %% The file wont be deleted on windows until it's closed, why we
+ %% need to rename instead.
+ ?line ok = file:rename(TmpEzFile,TmpEzFile++".moved");
+ _ ->
+ ?line ok = file:delete(TmpEzFile)
+ end,
test_server:capture_start(),
?line ok = code:clash(),
test_server:capture_stop(),
?line [BadPathMsg|_] = test_server:capture_get(),
?line true = lists:prefix("** Bad path can't read", BadPathMsg),
?line true = code:set_path(P),
+ file:delete(TmpEzFile++".moved"), %% Only effect on windows
ok.
ext_mod_dep(suite) ->
@@ -1145,6 +1155,22 @@ compile_files([File | Files], SrcDir, OutDir) ->
compile_files([], _, _) ->
ok.
+big_boot_embedded(suite) ->
+ [];
+big_boot_embedded(doc) ->
+ ["Test that a boot file with (almost) all of OTP can be used to start an"
+ " embeddedd system."];
+big_boot_embedded(Config) when is_list(Config) ->
+ ?line {BootArg,AppsInBoot} = create_big_boot(Config),
+ ?line {ok, Node} =
+ ?t:start_node(big_boot_embedded, slave,
+ [{args,"-boot "++BootArg++" -mode embedded"}]),
+ ?line RemoteNodeApps =
+ [ {X,Y} || {X,_,Y} <-
+ rpc:call(Node,application,loaded_applications,[]) ],
+ ?line true = lists:sort(AppsInBoot) =:= lists:sort(RemoteNodeApps),
+ ok.
+
on_load(Config) when is_list(Config) ->
Master = on_load_test_case_process,
@@ -1281,6 +1307,73 @@ create_script(Config) ->
?line file:close(Fd),
{filename:dirname(Name),filename:basename(Name)}.
+create_big_boot(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Options,Local} = case is_source_dir() of
+ true -> {[no_module_tests,local],true};
+ _ -> {[no_module_tests],false}
+ end,
+ ?line {LatestDir,LatestName,Apps} = create_big_script(Config,Local),
+ ?line ok = file:set_cwd(LatestDir),
+ ?line ok = systools:make_script(LatestName, Options),
+ ?line ok = file:set_cwd(OldDir),
+ {filename:join(LatestDir, LatestName),Apps}.
+
+% The following apps cannot be loaded
+% hipe .app references (or can reference) files that have no
+% corresponding beam file (if hipe is not enabled)
+filter_app("hipe",_) ->
+ false;
+% Dialyzer and typer depends on hipe
+filter_app("dialyzer",_) ->
+ false;
+filter_app("typer",_) ->
+ false;
+% Orber requires explicit configuration
+filter_app("orber",_) ->
+ false;
+% cos* depends on orber
+filter_app("cos"++_,_) ->
+ false;
+% ic has a mod instruction in the app file but no corresponding start function
+filter_app("ic",_) ->
+ false;
+% Netconf has some dependency that I really do not understand (maybe like orber)
+filter_app("netconf",_) ->
+ false;
+% Safe has the same kind of error in the .app file as ic
+filter_app("safe",_) ->
+ false;
+% OS_mon does not find it's port program when running cerl
+filter_app("os_mon",true) ->
+ false;
+% Other apps should be OK.
+filter_app(_,_) ->
+ true.
+create_big_script(Config,Local) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Name = filename:join(PrivDir,"full_script_test"),
+ ?line InitialApplications=application:loaded_applications(),
+ %% Applications left loaded by the application suite, unload them!
+ ?line UnloadFix=[app0,app1,app2,group_leader,app_start_error],
+ ?line [application:unload(Leftover) ||
+ Leftover <- UnloadFix,
+ lists:keymember(Leftover,1,InitialApplications) ],
+ %% Now we should have only "real" applications...
+ ?line [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)],
+ ?line Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()],
+ ?line {ok,Fd} = file:open(Name ++ ".rel", write),
+ ?line io:format(Fd,
+ "{release, {\"Test release 3\", \"P2A\"}, \n"
+ " {erts, \"9.42\"}, \n"
+ " ~p}.\n",
+ [Apps]),
+ ?line file:close(Fd),
+ ?line NewlyLoaded =
+ application:loaded_applications() -- InitialApplications,
+ ?line [ application:unload(N) || {N,_,_} <- NewlyLoaded],
+ {filename:dirname(Name),filename:basename(Name),Apps}.
+
is_source_dir() ->
filename:basename(code:lib_dir(kernel)) =:= "kernel" andalso
filename:basename(code:lib_dir(stdlib)) =:= "stdlib".
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index bbdfbd3cb0..2ff1d7210a 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -423,7 +423,11 @@ connect(Config) when is_list(Config) ->
?line ok = gen_udp:close(S1),
?line ok = gen_udp:connect(S2, Addr, P1),
?line ok = gen_udp:send(S2, <<16#deadbeef:32>>),
- ?line {error,econnrefused} = gen_udp:recv(S2, 0, 5),
+ ?line ok = case gen_udp:recv(S2, 0, 5) of
+ {error,econnrefused} -> ok;
+ {error,econnreset} -> ok;
+ Other -> Other
+ end,
ok.
implicit_inet6(Config) when is_list(Config) ->
diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src
index 47c9bf9979..22ef5178a7 100644
--- a/lib/mnesia/src/mnesia.appup.src
+++ b/lib/mnesia/src/mnesia.appup.src
@@ -1,7 +1,13 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.4.15",[
+ {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
+ ]}
],
[
+ {"4.4.15",[
+ {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
+ ]}
]
}.
diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl
index f669d009c6..644133cf5d 100644
--- a/lib/mnesia/src/mnesia_dumper.erl
+++ b/lib/mnesia/src/mnesia_dumper.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -643,7 +643,7 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) ->
true -> ignore;
false ->
mnesia_log:open_log(temp,
- mnesia_log:dcl_log_header(),
+ mnesia_log:dcd_log_header(),
Dcd,
false,
false,
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index bce0f7b739..5b52bc6075 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.4.15
+MNESIA_VSN = 4.4.16
diff --git a/lib/odbc/src/odbc.appup.src b/lib/odbc/src/odbc.appup.src
index e95e542ff5..f1a370d925 100644
--- a/lib/odbc/src/odbc.appup.src
+++ b/lib/odbc/src/odbc.appup.src
@@ -1 +1,8 @@
-{"%VSN%", [],[]}
+%% -*- erlang -*-
+{"%VSN%",
+ [
+ {"2.10.8", [{restart_application, ssl}]}
+ ],
+ [
+ {"2.10.8", [{restart_application, ssl}]}
+ ]}.
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index fac3f06d4b..aacf3924db 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.10.8
+ODBC_VSN = 2.10.9
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index c8953c6818..fadb993ed9 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -164,7 +164,7 @@ validate_signature(OtpCert, DerCert, Key, KeyParams,
verify_fun(OtpCert, {bad_cert, invalid_signature}, UserState, VerifyFun)
end.
%%--------------------------------------------------------------------
--spec validate_names(#'OTPCertificate'{}, list(), list(),
+-spec validate_names(#'OTPCertificate'{}, no_constraints | list(), list(),
term(), term(), fun())-> term().
%%
%% Description: Validate Subject Alternative Name.
diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src
index 0f9f62d2f6..6b6b76d0a5 100644
--- a/lib/public_key/src/public_key.appup.src
+++ b/lib/public_key/src/public_key.appup.src
@@ -1,6 +1,12 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"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, []},
@@ -12,6 +18,12 @@
}
],
[
+ {"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, []},
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 095a6ff0e0..30398df9cc 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -213,10 +213,13 @@ decrypt_private(CipherText,
crypto:mpint(D)], Padding).
%%--------------------------------------------------------------------
--spec decrypt_public(CipherText :: binary(), rsa_public_key()) ->
+-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
PlainText :: binary().
--spec decrypt_public(CipherText :: binary(), rsa_public_key(),
+-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key(),
public_crypt_options()) -> PlainText :: binary().
+%% NOTE: The rsa_private_key() is not part of the documented API it is
+%% here for testing purposes, in a real situation this is not a relevant
+%% thing to do.
%%
%% Description: Public key decryption using the public key.
%%--------------------------------------------------------------------
@@ -232,10 +235,14 @@ decrypt_public(CipherText,#'RSAPrivateKey'{modulus = N, publicExponent = E},
decrypt_public(CipherText, N,E, Options).
%%--------------------------------------------------------------------
--spec encrypt_public(PlainText :: binary(), rsa_public_key()) ->
+-spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key()) ->
CipherText :: binary().
--spec encrypt_public(PlainText :: binary(), rsa_public_key(),
+-spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key(),
public_crypt_options()) -> CipherText :: binary().
+
+%% NOTE: The rsa_private_key() is not part of the documented API it is
+%% here for testing purposes, in a real situation this is not a relevant
+%% thing to do.
%%
%% Description: Public key encryption using the public key.
%%--------------------------------------------------------------------
@@ -280,8 +287,8 @@ encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N,
sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E,
privateExponent = D})
when is_binary(PlainText),
- DigestType == md5;
- DigestType == sha ->
+ (DigestType == md5 orelse
+ DigestType == sha) ->
crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E),
crypto:mpint(N),
@@ -571,11 +578,9 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
-sized_binary(Binary) when is_binary(Binary) ->
+sized_binary(Binary) ->
Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>;
-sized_binary(List) ->
- sized_binary(list_to_binary(List)).
+ <<?UINT32(Size), Binary/binary>>.
%%--------------------------------------------------------------------
%%% Deprecated functions
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 81e01f3a02..88cfbcf2b6 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -249,10 +249,8 @@ sign_verify(Config) when is_list(Config) ->
true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}),
%% RSA sign
- Msg0 = lists:duplicate(5, "Foo bar 100"),
- Msg = list_to_binary(Msg0),
+ Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
- RSASign = public_key:sign(Msg0, sha, PrivateRSA),
RSASign = public_key:sign(Msg, sha, PrivateRSA),
true = public_key:verify(Msg, sha, RSASign, PublicRSA),
false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA),
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 2810942171..334b9d792e 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.9
+PUBLIC_KEY_VSN = 0.10
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 511f1e0bb2..ec272379bb 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -218,12 +218,12 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
application is encountered. Additionally it will be called
when a certificate is considered valid by the path validation
to allow access to each certificate in the path to the user
- application. Note that the it will differentiate between
- the peer certificate and CA certificates by using valid_peer
- or valid as the second argument to the verify fun.
- See
- <seealso marker="public_key:application">public_key(3)</seealso>
- for definition of #'OTPCertificate'{} and #'Extension'{}.</p>
+ application. Note that the it will differentiate between the
+ peer certificate and CA certificates by using valid_peer or
+ valid as the second argument to the verify fun. See <seealso
+ marker="public_key:cert_records">the public_key User's
+ Guide</seealso> for definition of #'OTPCertificate'{} and
+ #'Extension'{}.</p>
<p>If the verify callback fun returns {fail, Reason}, the
verification process is immediately stopped and an alert is
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index f4e6b59b6d..51c5289bd2 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,9 +1,11 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
],
[
+ {"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
]}.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 5571fb01f6..8c0c2bfa5d 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -28,7 +28,6 @@
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([trusted_cert_and_path/2,
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 1c8bbbaf06..72f02a4362 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -29,7 +29,6 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([security_parameters/2, suite_definition/1,
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index ce90d22c09..6c9ac65b64 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -29,7 +29,6 @@
-behaviour(gen_fsm).
--include("ssl_debug.hrl").
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
-include("ssl_record.hrl").
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 7082a23fd0..c7a1c4965d 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -28,7 +28,6 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/5, server_hello/4, hello/4,
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 74fba3786c..68a7802ef2 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -26,6 +26,13 @@
-ifndef(ssl_handshake).
-define(ssl_handshake, true).
+-include_lib("public_key/include/public_key.hrl").
+
+-type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
+-type public_key() :: #'RSAPublicKey'{} | integer().
+-type public_key_params() :: #'Dss-Parms'{} | term().
+-type public_key_info() :: {algo_oid(), public_key(), public_key_params()}.
+
-record(session, {
session_id,
peer_certificate,
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 4148032cb7..43a85c2d9d 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -25,6 +25,24 @@
-include_lib("public_key/include/public_key.hrl").
+-type reason() :: term().
+-type reply() :: term().
+-type msg() :: term().
+-type from() :: term().
+-type host() :: string() | tuple().
+-type port_num() :: integer().
+-type session_id() :: 0 | binary().
+-type tls_version() :: {integer(), integer()}.
+-type tls_atom_version() :: sslv3 | tlsv1.
+-type cache_ref() :: term().
+-type certdb_ref() :: term().
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type der_cert() :: binary().
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type issuer() :: tuple().
+-type serialnumber() :: integer().
+-type cert_key() :: {reference(), integer(), issuer()}.
+
%% basic binary constructors
-define(BOOLEAN(X), X:8/unsigned-big-integer).
-define(BYTE(X), X:8/unsigned-big-integer).
@@ -93,28 +111,6 @@
active = true
}).
--type reason() :: term().
--type reply() :: term().
--type msg() :: term().
--type from() :: term().
--type host() :: string() | tuple().
--type port_num() :: integer().
--type session_id() :: 0 | binary().
--type tls_version() :: {integer(), integer()}.
--type tls_atom_version() :: sslv3 | tlsv1.
--type cache_ref() :: term().
--type certdb_ref() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
--type oid() :: tuple().
--type public_key() :: #'RSAPublicKey'{} | integer().
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {oid(), public_key(), public_key_params()}.
--type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
--type issuer() :: tuple().
--type serialnumber() :: integer().
--type cert_key() :: {reference(), integer(), issuer()}.
-
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index e7a2d8ecf1..f1c0073965 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -30,7 +30,6 @@
-include("ssl_alert.hrl").
-include("ssl_handshake.hrl").
-include("ssl_cipher.hrl").
--include("ssl_debug.hrl").
%% Connection state handling
-export([init_connection_states/1,
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index 18c3f4ed3d..c49f9f1e6d 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -25,7 +25,6 @@
-module(ssl_ssl3).
-include("ssl_cipher.hrl").
--include("ssl_debug.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl"). % MD5 and SHA
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 88394b23ba..3784483e9c 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -27,7 +27,6 @@
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
--include("ssl_debug.hrl").
-export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7,
setup_keys/6, suites/0]).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ea84b3c9d1..8f9554f3ce 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -31,6 +31,7 @@
-define('24H_in_sec', 86400).
-define(TIMEOUT, 60000).
+-define(LONG_TIMEOUT, 600000).
-define(EXPIRE, 10).
-define(SLEEP, 500).
@@ -45,7 +46,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
crypto:start(),
application:start(public_key),
ssl:start(),
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 7a441e4599..0f39759d97 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -28,6 +28,7 @@
-define(SLEEP, 500).
-define(TIMEOUT, 60000).
+-define(LONG_TIMEOUT, 600000).
-behaviour(ssl_session_cache_api).
%% For the session cache tests
@@ -45,7 +46,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
crypto:start(),
application:start(public_key),
ssl:start(),
@@ -119,7 +120,7 @@ end_per_testcase(session_cache_process_list, Config) ->
end_per_testcase(session_cache_process_mnesia, Config) ->
application:unset_env(ssl, session_cb),
application:unset_env(ssl, session_cb_init_args),
- mnesia:stop(),
+ mnesia:kill(),
ssl:stop(),
ssl:start(),
end_per_testcase(default_action, Config);
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 55a0100b1e..afedeaf099 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -27,6 +27,7 @@
-include("test_server.hrl").
-define(TIMEOUT, 120000).
+-define(LONG_TIMEOUT, 600000).
-define(SLEEP, 1000).
-define(OPENSSL_RENEGOTIATE, "r\n").
-define(OPENSSL_QUIT, "Q\n").
@@ -44,7 +45,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
case os:find_executable("openssl") of
false ->
{skip, "Openssl not found"};
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 30a0a3b3f7..ee692adb3b 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1,2 +1,2 @@
-SSL_VSN = 4.1
+SSL_VSN = 4.1.1
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index ad100d2cf5..b002af6616 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -816,7 +816,7 @@ ok
</item>
<item>
<p><c>{max_no_slots, no_slots()}</c>, the maximum number
- of slots that will be used. The default value is 2 M, and
+ of slots that will be used. The default value as well as
the maximal value is 32 M. Note that a higher value may
increase the fragmentation of the table, and conversely,
that a smaller value may decrease the fragmentation, at
diff --git a/lib/stdlib/src/dets.hrl b/lib/stdlib/src/dets.hrl
index 6e59770753..fbffc9d008 100644
--- a/lib/stdlib/src/dets.hrl
+++ b/lib/stdlib/src/dets.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -18,7 +18,7 @@
%%
-define(DEFAULT_MIN_NO_SLOTS, 256).
--define(DEFAULT_MAX_NO_SLOTS, 2*1024*1024).
+-define(DEFAULT_MAX_NO_SLOTS, 32*1024*1024).
-define(DEFAULT_AUTOSAVE, 3). % minutes
-define(DEFAULT_CACHE, {3000, 14000}). % {delay,size} in {milliseconds,bytes}
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 2d8eb08105..b621b17441 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -5231,8 +5231,6 @@ smp_select_delete(Config) when is_list(Config) ->
types(doc) -> ["Test different types"];
types(Config) when is_list(Config) ->
init_externals(),
- io:format("ets:i() before test:\n",[]),
- ets:i(), % SVERK: trouble shooting
repeat_for_opts(types_do,[[set,ordered_set],compressed]).
types_do(Opts) ->
@@ -5328,6 +5326,10 @@ my_tab_to_list(Ts,Key, Acc) ->
my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)| Acc]).
etsmem() ->
+ 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()),
+ Mem =
{try erlang:memory(ets) catch error:notsup -> notsup end,
case erlang:system_info({allocator,ets_alloc}) of
false -> undefined;
@@ -5346,12 +5348,13 @@ etsmem() ->
{value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L),
{Bl0+Bl,BlSz0+BlSz}
end, {0,0}, MSBCS)
- end}.
+ end},
+ {Mem,AllTabs}.
-verify_etsmem(MemInfo) ->
+verify_etsmem({MemInfo,AllTabs}) ->
wait_for_test_procs(),
case etsmem() of
- MemInfo ->
+ {MemInfo,_} ->
io:format("Ets mem info: ~p", [MemInfo]),
case MemInfo of
{ErlMem,EtsAlloc} when ErlMem == notsup; EtsAlloc == undefined ->
@@ -5360,13 +5363,15 @@ verify_etsmem(MemInfo) ->
_ ->
ok
end;
- Other ->
+ {MemInfo2, AllTabs2} ->
io:format("Expected: ~p", [MemInfo]),
- io:format("Actual: ~p", [Other]),
- ets:i(),
+ io:format("Actual: ~p", [MemInfo2]),
+ io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
+ io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
?t:fail()
end.
+
start_loopers(N, Prio, Fun, State) ->
lists:map(fun (_) ->
my_spawn_opt(fun () -> looper(Fun, State) end,
diff --git a/lib/tools/src/eprof.erl b/lib/tools/src/eprof.erl
index 8e5c0ec46b..87fdc1fa34 100644
--- a/lib/tools/src/eprof.erl
+++ b/lib/tools/src/eprof.erl
@@ -136,7 +136,7 @@ handle_call({analyze, procs, Opts}, _, #state{ bpd = #bpd{ p = Ps, us = Tus} = B
lists:foreach(fun
({Pid, Mfas}) ->
{Pn, Pus} = sum_bp_total_n_us(Mfas),
- format(Fd, "~n****** Process ~w -- ~s % of profiled time *** ~n", [Pid, s("~.2f", [100.0*(Pus/Tus)])]),
+ format(Fd, "~n****** Process ~w -- ~s % of profiled time *** ~n", [Pid, s("~.2f", [100.0*divide(Pus,Tus)])]),
print_bp_mfa(Mfas, {Pn,Pus}, Fd, Opts),
ok
end, gb_trees:to_list(Ps)),
@@ -443,8 +443,8 @@ string_bp_mfa([{Mfa, {Count, Time}}|Mfas], Tus, {MfaW, CountW, PercW, TimeW, TpC
Smfa = s(Mfa),
Scount = s(Count),
Stime = s(Time),
- Sperc = s("~.2f", [100*(Time/Tus)]),
- Stpc = s("~.2f", [Time/Count]),
+ Sperc = s("~.2f", [100*divide(Time,Tus)]),
+ Stpc = s("~.2f", [divide(Time,Count)]),
string_bp_mfa(Mfas, Tus, {
erlang:max(MfaW, length(Smfa)),
@@ -484,3 +484,6 @@ format(Fd, Format, Strings) ->
io:format(Fd, Format, Strings),
io:format(Format, Strings),
ok.
+
+divide(_,0) -> 0.0;
+divide(T,N) -> T/N.
diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
index 9d184152d1..3b9eaa309c 100644
--- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
@@ -1,7 +1,7 @@
%%-*-erlang-*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -934,6 +934,13 @@ parse_att_value(?STRING_REST("&", Rest), State, Stop, Acc) ->
parse_att_value(Rest1, State2, Stop, ParsedValue ++ Acc);
{external_general, Name, _} ->
?fatal_error(State1, "External parsed entity reference in attribute value: " ++ Name);
+ {not_found, Name} ->
+ case State#xmerl_sax_parser_state.skip_external_dtd of
+ false ->
+ ?fatal_error(State1, "Entity not declared: " ++ Name); %%VC: Entity Declared
+ true ->
+ parse_att_value(Rest1, State1, Stop, ";" ++ lists:reverse(Name) ++ "&" ++ Acc)
+ end;
{unparsed, Name, _} ->
?fatal_error(State1, "Unparsed entity reference in attribute value: " ++ Name)
end;
@@ -1098,6 +1105,13 @@ parse_content(?STRING_REST("&", Rest), State, Acc, _IgnorableWS) ->
{external_general, _, {PubId, SysId}} ->
State2 = parse_external_entity(State1, PubId, SysId),
parse_content(Rest1, State2, Acc, false);
+ {not_found, Name} ->
+ case State#xmerl_sax_parser_state.skip_external_dtd of
+ false ->
+ ?fatal_error(State1, "Entity not declared: " ++ Name); %%VC: Entity Declared
+ true ->
+ parse_content(Rest1, State1, ";" ++ lists:reverse(Name) ++ "&" ++ Acc, false)
+ end;
{unparsed, Name, _} ->
?fatal_error(State1, "Unparsed entity reference in content: " ++ Name)
end;
@@ -1357,7 +1371,7 @@ look_up_reference(Name, HaveToExist, State) ->
yes ->
?fatal_error(State, "Entity not declared: " ++ Name); %%WFC: Entity Declared
no ->
- ?fatal_error(State, "Entity not declared: " ++ Name) %%VC: Entity Declared
+ {not_found, Name} %%VC: Entity Declared
end;
false ->
{not_found, Name}
@@ -1869,7 +1883,14 @@ parse_doctype_decl(?STRING_REST("%", Rest), State) ->
parse_doctype_decl(?APPEND_STRING(IValue, Rest1), State1);
{external_parameter, _, {PubId, SysId}} ->
State2 = parse_external_entity(State1#xmerl_sax_parser_state{file_type = entity}, PubId, SysId),
- parse_doctype_decl(Rest1, State2)
+ parse_doctype_decl(Rest1, State2);
+ {not_found, Name} ->
+ case State#xmerl_sax_parser_state.skip_external_dtd of
+ false ->
+ ?fatal_error(State1, "Entity not declared: " ++ Name); %%WFC: Entity Declared
+ true ->
+ parse_doctype_decl(Rest1, State1)
+ end
end;
parse_doctype_decl(?STRING_REST("<!", Rest1), State) ->
parse_doctype_decl_1(Rest1, State);
@@ -2443,7 +2464,7 @@ parse_ndata(Bytes, State) ->
%% Acc = string()
%% Result : {Value, Rest, State}
%% Value = string()
-%% Description: Parse an attribute value
+%% Description: Parse an entity value
%%----------------------------------------------------------------------
parse_entity_value(?STRING_EMPTY, State, undefined, Acc) ->
{Acc, [], State}; %% stop clause when parsing references
@@ -2473,7 +2494,7 @@ parse_entity_value(?STRING_REST("&", Rest), State, Stop, Acc) ->
{external_general, Name, _} ->
parse_entity_value(Rest1, State1, Stop, ";" ++ lists:reverse(Name) ++ "&" ++ Acc);
{not_found, Name} ->
- parse_entity_value(Rest1, State1, Stop, ";" ++ lists:reverse(Name) ++ "&" ++ Acc);
+ parse_entity_value(Rest1, State1, Stop, ";" ++ lists:reverse(Name) ++ "&" ++ Acc);
{unparsed, Name, _} ->
?fatal_error(State1, "Unparsed entity reference in entity value: " ++ Name)
end;
@@ -2490,7 +2511,15 @@ parse_entity_value(?STRING_REST("%", Rest), #xmerl_sax_parser_state{file_type=Ty
IValue = ?TO_INPUT_FORMAT(" " ++ RefValue ++ " "),
parse_entity_value(?APPEND_STRING(IValue, Rest1), State1, Stop, Acc);
{external_parameter, _, {_PubId, _SysId}} ->
- ?fatal_error(State1, "Parameter references in entity value not supported yet.")
+ ?fatal_error(State1, "Parameter references in entity value not supported yet.");
+ {not_found, Name} ->
+ case State#xmerl_sax_parser_state.skip_external_dtd of
+ false ->
+ ?fatal_error(State1, "Entity not declared: " ++ Name); %%VC: Entity Declared
+ true ->
+ parse_entity_value(Rest1, State1, Stop, ";" ++ lists:reverse(Name) ++ "&" ++ Acc)
+ end
+
end
end;
parse_entity_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index e2e6f95c4a..e07d495fc7 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -34,7 +34,9 @@
%% See also <a href="xmerl_examples.html">tutorial</a> on customization
%% functions.
%% </p>
+%% <p>
%% Possible options are:
+%% </p>
%% <dl>
%% <dt><code>{acc_fun, Fun}</code></dt>
%% <dd>Call back function to accumulate contents of entity.</dd>
diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl
index 182a186d2c..e654a8ef1d 100644
--- a/lib/xmerl/src/xmerl_xpath.erl
+++ b/lib/xmerl/src/xmerl_xpath.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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
@@ -57,7 +57,9 @@
%% @type option_list(). <p>Options allows to customize the behaviour of the
%% XPath scanner.
%% </p>
+%% <p>
%% Possible options are:
+%% </p>
%% <dl>
%% <dt><code>{namespace, #xmlNamespace}</code></dt>
%% <dd>Set namespace nodes, from XmlNamspace, in xmlContext</dd>
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index 1aedc9e270..c0923520c2 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -29,7 +29,9 @@
%% @type option_list(). <p>Options allow to customize the behaviour of the
%% validation.
%% </p>
+%% <p>
%% Possible options are :
+%% </p>
%% <dl>
%% <dt><code>{tab2file,boolean()}</code></dt>
%% <dd>Enables saving of abstract structure on file for debugging
@@ -46,6 +48,7 @@
%% <dd>It is possible by this option to provide a state with process
%% information from an earlier validation.</dd>
%% </dl>
+%% @end
%%%-------------------------------------------------------------------
-module(xmerl_xsd).
diff --git a/make/otp.mk.in b/make/otp.mk.in
index 6ae7c5b456..bf287be416 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -209,6 +209,8 @@ MAN9DIR = $(DOCDIR)/man9
TEXDIR = .
+SPECDIR = $(DOCDIR)/specs
+
# HTML & GIF files that always are generated and must be delivered
SGML_COLL_FILES = $(SGML_APPLICATION_FILES) $(SGML_PART_FILES)
XML_COLL_FILES = $(XML_APPLICATION_FILES) $(XML_PART_FILES)
@@ -237,41 +239,52 @@ FOP = @FOP@
DOCGEN=$(ERL_TOP)/lib/erl_docgen
+SPECS_ESRC = ../../src
+# Extract specifications and types from Erlang source files (-spec, -type)
+$(SPECDIR)/specs_%.xml: $(SPECS_ESRC)/%.erl
+ escript $(DOCGEN)/priv/bin/specs_gen.escript $(SPECS_FLAGS) -o$(dir $@) $<
-$(MAN1DIR)/%.1:: %.xml
+$(MAN1DIR)/%.1: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-$(MAN2DIR)/%.2:: %.xml
+$(MAN2DIR)/%.2: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-$(MAN3DIR)/%.3:: %.xml
+ifneq ($(wildcard $(SPECDIR)),)
+$(MAN3DIR)/%.3: %.xml $(SPECDIR)/specs_%.xml
+ date=`date +"%B %e %Y"`; \
+ specs_file=`pwd`/$(SPECDIR)/specs_$*.xml; \
+ xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --stringparam specs_file "$$specs_file" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
+else
+$(MAN3DIR)/%.3: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
+endif
# left for compatability
-$(MAN4DIR)/%.4:: %.xml
+$(MAN4DIR)/%.4: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-$(MAN4DIR)/%.5:: %.xml
+$(MAN4DIR)/%.5: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
# left for compatability
-$(MAN6DIR)/%.6:: %_app.xml
+$(MAN6DIR)/%.6: %_app.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-$(MAN6DIR)/%.7:: %_app.xml
+$(MAN6DIR)/%.7: %_app.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-$(MAN9DIR)/%.9:: %.xml
+$(MAN9DIR)/%.9: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index 7d433e738c..8058e634d4 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -21,13 +21,30 @@
# Targets for the new documentation support
# ----------------------------------------------------
+ifneq ($(TOP_SPECS_FILE),)
+TOP_SPECS_PARAM = --stringparam specs_file "`pwd`/$(TOP_SPECS_FILE)"
+endif
+
+MOD2APP = $(ERL_TOP)/make/$(TARGET)/mod2app.xml
+ifneq ($(wildcard $(MOD2APP)),)
+MOD2APP_PARAM = --stringparam mod2app_file "$(MOD2APP)"
+endif
+
ifeq ($(TOPDOC),)
-$(HTMLDIR)/index.html: $(XML_FILES)
+$(HTMLDIR)/index.html: $(XML_FILES) $(SPECS_FILES)
date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
- --stringparam pdfdir "$(PDFDIR)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml
+ $(XSLTPROC) --noout \
+ --stringparam outdir $(HTMLDIR) \
+ --stringparam docgen "$(DOCGEN)" \
+ --stringparam topdocdir "$(TOPDOCDIR)" \
+ --stringparam pdfdir "$(PDFDIR)" \
+ --xinclude $(TOP_SPECS_PARAM) $(MOD2APP_PARAM) \
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ -path $(DOCGEN)/priv/docbuilder_dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
+ $(DOCGEN)/priv/xsl/db_html.xsl book.xml
endif
$(HTMLDIR)/users_guide.html: $(XML_FILES)
@@ -37,14 +54,17 @@ $(HTMLDIR)/users_guide.html: $(XML_FILES)
--stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
-path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml
-
-%.fo: $(XML_FILES)
+%.fo: $(XML_FILES) $(SPECS_FILES)
date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \
- --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@
-
-
+ $(XSLTPROC) \
+ --stringparam docgen "$(DOCGEN)" \
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ --xinclude $(TOP_SPECS_PARAM) \
+ -path $(DOCGEN)/priv/docbuilder_dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
+ $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@
# ------------------------------------------------------------------------
# The following targets just exist in the documentation directory