diff options
105 files changed, 3379 insertions, 693 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/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/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/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/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) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="init-1"/> + </desc></func> +<func> +<name>post_end_group(Group, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="post_end_group-3"/> + </desc></func> +<func> +<name>post_end_suite(Suite, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="post_end_suite-3"/> + </desc></func> +<func> +<name>post_end_tc(TC, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="post_end_tc-3"/> + </desc></func> +<func> +<name>post_init_group(Group, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="post_init_group-3"/> + </desc></func> +<func> +<name>post_init_suite(Suite, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="post_init_suite-3"/> + </desc></func> +<func> +<name>pre_end_group(Group, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="pre_end_group-3"/> + </desc></func> +<func> +<name>pre_end_suite(Suite, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="pre_end_suite-3"/> + </desc></func> +<func> +<name>pre_init_group(Group, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="pre_init_group-3"/> + </desc></func> +<func> +<name>pre_init_suite(Suite, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="pre_init_suite-3"/> + </desc></func> +<func> +<name>pre_init_tc(TC, Config, State) -> term() +</name> +<fsummary> </fsummary> + +<desc><marker id="pre_init_tc-3"/> + </desc></func> +<func> +<name>terminate(Config, State) -> 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/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 895089846a..b4161ea194 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -385,7 +385,7 @@ message_to_string({spec_missing_fun, [M, F, A]}) -> [M, F, A]); %%----- Warnings for opaque type violations ------------------- message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}) -> - io_lib:format("The call ~w:~w~s contains ~s argument when ~s\n", + io_lib:format("The call ~w:~w~s contains ~s when ~s\n", [M, F, Args, form_positions(ArgNs), form_expected(ExpArgs)]); message_to_string({call_without_opaque, [M, F, Args, ExpectedTriples]}) -> io_lib:format("The call ~w:~w~s does not have ~s\n", 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/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> </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/>  @@ -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..2ed0d95c6d 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> .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> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .fi</xsl:text> + </xsl:template> + + <xsl:template name="guard"> + <xsl:param name="guard"/> + <xsl:param name="type_desc"/> + <xsl:text> .RS</xsl:text> + <xsl:text> .TP</xsl:text> + <xsl:text> 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> .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> </xsl:text> + <xsl:apply-templates select="string"/> + <xsl:text> .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> </xsl:text><xsl:apply-templates/> + <xsl:text> .br</xsl:text> + </xsl:template> + + <!-- Datatypes --> + <xsl:template match="datatypes"> + <xsl:text> .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> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .fi</xsl:text> + </xsl:template> + + <xsl:template match="local_defs"> + <xsl:text> .RS</xsl:text> + <xsl:apply-templates/> + <xsl:text> .RE</xsl:text> + </xsl:template> + + <xsl:template match="local_def"> + <xsl:text> </xsl:text> + <xsl:apply-templates/> + <xsl:text> .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> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .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> .SH "</xsl:text><xsl:value-of select="translate(title, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:text>" </xsl:text> @@ -49,7 +319,7 @@ <!-- Lists --> - + <xsl:template match="list"> <xsl:text> .RS 2</xsl:text> <xsl:apply-templates/> @@ -68,7 +338,7 @@ <xsl:apply-templates select="tag|item"/> <xsl:text> .RE</xsl:text> </xsl:template> - + <xsl:template match="taglist/tag"> <xsl:text> .TP 2 </xsl:text> <xsl:text>.B </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> .RS 2</xsl:text> - <xsl:text> .LP .LP </xsl:text> + <xsl:text> .RS 2</xsl:text> + <xsl:text> .LP .LP </xsl:text> <xsl:value-of select="$content"/> - <xsl:text> .RE</xsl:text> + <xsl:text> .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" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text> </xsl:text> + <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text> </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" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text> </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" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text> </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" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text> </xsl:text> + <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text> </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" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -271,10 +541,26 @@ <!-- Func --> <xsl:template match="func"> <xsl:text> .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> .B </xsl:text> <xsl:apply-templates/> <xsl:text> .br</xsl:text> @@ -296,7 +582,7 @@ <xsl:text> </xsl:text><xsl:value-of select="normalize-space(text())"/> <xsl:text> .br</xsl:text> </xsl:template> - + <!-- D --> <xsl:template match="d"> <xsl:text> </xsl:text><xsl:apply-templates/> @@ -316,7 +602,7 @@ <!-- This tag is skipped for now. --> </xsl:template> - + <!-- Authors --> <xsl:template match="authors"> <xsl:text> .SH AUTHORS</xsl:text> @@ -336,21 +622,11 @@ <xsl:text>></xsl:text> </xsl:template> - <!-- Do not noramlize any text within pre and code tags. --> - <xsl:template match="pre/text()"> - <xsl:value-of select="."/> - </xsl:template> - - <xsl:template match="code/text()"> - <xsl:value-of select="."/> - </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> </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/>  <xsl:value-of select="header/title"/> </fo:marker> <xsl:value-of select="$partnum"/>.<xsl:number/>  <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"/>    <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/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/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_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_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_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/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/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/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.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/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_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/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/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 5bdd1a8672..7102fb9f6e 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -668,14 +668,15 @@ terminate_children([], _SupName, Res) -> Res. do_terminate(Child, SupName) when Child#child.pid =/= undefined -> - case shutdown(Child#child.pid, - Child#child.shutdown) of - ok -> - Child#child{pid = undefined}; - {error, OtherReason} -> - report_error(shutdown_error, OtherReason, Child, SupName), - Child#child{pid = undefined} - end; + case shutdown(Child#child.pid, Child#child.shutdown) of + ok -> + ok; + {error, normal} when Child#child.restart_type =/= permanent -> + ok; + {error, OtherReason} -> + report_error(shutdown_error, OtherReason, Child, SupName) + end, + Child#child{pid = undefined}; do_terminate(Child, _SupName) -> Child. 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/wx/c_src/wxe_return.cpp b/lib/wx/c_src/wxe_return.cpp index 2c4f7541e7..9fd627829e 100644 --- a/lib/wx/c_src/wxe_return.cpp +++ b/lib/wx/c_src/wxe_return.cpp @@ -64,11 +64,14 @@ int wxeReturn::send() { int res = driver_send_term(port, caller, rtData, rtLength); driver_free(rtData); +#ifdef DEBUG if(res == -1) { wxString msg; msg.Printf(wxT("Failed to send return or event msg")); send_msg("internal_error", &msg); } +#endif + reset(); return res; } diff --git a/lib/wx/src/gen/wxSystemSettings.erl b/lib/wx/src/gen/wxSystemSettings.erl new file mode 100644 index 0000000000..3f7e0a1ad6 --- /dev/null +++ b/lib/wx/src/gen/wxSystemSettings.erl @@ -0,0 +1,79 @@ +%% +%% %CopyrightBegin% +%% +%% 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html">wxSystemSettings</a>. +%% @type wxSystemSettings(). An object reference, The representation is internal +%% and can be changed without notice. It can't be used for comparsion +%% stored on disc or distributed for use on other nodes. + +-module(wxSystemSettings). +-include("wxe.hrl"). +-export([getColour/1,getFont/1,getMetric/1,getMetric/2,getScreenType/0]). + +%% inherited exports +-export([parent_class/1]). + +%% @hidden +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +%% @spec (Index::WxSystemColour) -> wx:colour() +%% WxSystemColour = integer() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html#wxsystemsettingsgetcolour">external documentation</a>. +%%<br /> WxSystemColour is one of ?wxSYS_COLOUR_SCROLLBAR | ?wxSYS_COLOUR_BACKGROUND | ?wxSYS_COLOUR_DESKTOP | ?wxSYS_COLOUR_ACTIVECAPTION | ?wxSYS_COLOUR_INACTIVECAPTION | ?wxSYS_COLOUR_MENU | ?wxSYS_COLOUR_WINDOW | ?wxSYS_COLOUR_WINDOWFRAME | ?wxSYS_COLOUR_MENUTEXT | ?wxSYS_COLOUR_WINDOWTEXT | ?wxSYS_COLOUR_CAPTIONTEXT | ?wxSYS_COLOUR_ACTIVEBORDER | ?wxSYS_COLOUR_INACTIVEBORDER | ?wxSYS_COLOUR_APPWORKSPACE | ?wxSYS_COLOUR_HIGHLIGHT | ?wxSYS_COLOUR_HIGHLIGHTTEXT | ?wxSYS_COLOUR_BTNFACE | ?wxSYS_COLOUR_3DFACE | ?wxSYS_COLOUR_BTNSHADOW | ?wxSYS_COLOUR_3DSHADOW | ?wxSYS_COLOUR_GRAYTEXT | ?wxSYS_COLOUR_BTNTEXT | ?wxSYS_COLOUR_INACTIVECAPTIONTEXT | ?wxSYS_COLOUR_BTNHIGHLIGHT | ?wxSYS_COLOUR_BTNHILIGHT | ?wxSYS_COLOUR_3DHIGHLIGHT | ?wxSYS_COLOUR_3DHILIGHT | ?wxSYS_COLOUR_3DDKSHADOW | ?wxSYS_COLOUR_3DLIGHT | ?wxSYS_COLOUR_INFOTEXT | ?wxSYS_COLOUR_INFOBK | ?wxSYS_COLOUR_LISTBOX | ?wxSYS_COLOUR_HOTLIGHT | ?wxSYS_COLOUR_GRADIENTACTIVECAPTION | ?wxSYS_COLOUR_GRADIENTINACTIVECAPTION | ?wxSYS_COLOUR_MENUHILIGHT | ?wxSYS_COLOUR_MENUBAR | ?wxSYS_COLOUR_LISTBOXTEXT | ?wxSYS_COLOUR_MAX +getColour(Index) + when is_integer(Index) -> + wxe_util:call(?wxSystemSettings_GetColour, + <<Index:32/?UI>>). + +%% @spec (Index::WxSystemFont) -> wxFont:wxFont() +%% WxSystemFont = integer() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html#wxsystemsettingsgetfont">external documentation</a>. +%%<br /> WxSystemFont is one of ?wxSYS_OEM_FIXED_FONT | ?wxSYS_ANSI_FIXED_FONT | ?wxSYS_ANSI_VAR_FONT | ?wxSYS_SYSTEM_FONT | ?wxSYS_DEVICE_DEFAULT_FONT | ?wxSYS_DEFAULT_PALETTE | ?wxSYS_SYSTEM_FIXED_FONT | ?wxSYS_DEFAULT_GUI_FONT | ?wxSYS_ICONTITLE_FONT +getFont(Index) + when is_integer(Index) -> + wxe_util:call(?wxSystemSettings_GetFont, + <<Index:32/?UI>>). + +%% @spec (Index::WxSystemMetric) -> integer() +%% @equiv getMetric(Index, []) +getMetric(Index) + when is_integer(Index) -> + getMetric(Index, []). + +%% @spec (Index::WxSystemMetric, [Option]) -> integer() +%% Option = {win, wxWindow:wxWindow()} +%% WxSystemMetric = integer() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html#wxsystemsettingsgetmetric">external documentation</a>. +%%<br /> WxSystemMetric is one of ?wxSYS_MOUSE_BUTTONS | ?wxSYS_BORDER_X | ?wxSYS_BORDER_Y | ?wxSYS_CURSOR_X | ?wxSYS_CURSOR_Y | ?wxSYS_DCLICK_X | ?wxSYS_DCLICK_Y | ?wxSYS_DRAG_X | ?wxSYS_DRAG_Y | ?wxSYS_EDGE_X | ?wxSYS_EDGE_Y | ?wxSYS_HSCROLL_ARROW_X | ?wxSYS_HSCROLL_ARROW_Y | ?wxSYS_HTHUMB_X | ?wxSYS_ICON_X | ?wxSYS_ICON_Y | ?wxSYS_ICONSPACING_X | ?wxSYS_ICONSPACING_Y | ?wxSYS_WINDOWMIN_X | ?wxSYS_WINDOWMIN_Y | ?wxSYS_SCREEN_X | ?wxSYS_SCREEN_Y | ?wxSYS_FRAMESIZE_X | ?wxSYS_FRAMESIZE_Y | ?wxSYS_SMALLICON_X | ?wxSYS_SMALLICON_Y | ?wxSYS_HSCROLL_Y | ?wxSYS_VSCROLL_X | ?wxSYS_VSCROLL_ARROW_X | ?wxSYS_VSCROLL_ARROW_Y | ?wxSYS_VTHUMB_Y | ?wxSYS_CAPTION_Y | ?wxSYS_MENU_Y | ?wxSYS_NETWORK_PRESENT | ?wxSYS_PENWINDOWS_PRESENT | ?wxSYS_SHOW_SOUNDS | ?wxSYS_SWAP_BUTTONS +getMetric(Index, Options) + when is_integer(Index),is_list(Options) -> + MOpts = fun({win, #wx_ref{type=WinT,ref=WinRef}}, Acc) -> ?CLASS(WinT,wxWindow),[<<1:32/?UI,WinRef:32/?UI>>|Acc]; + (BadOpt, _) -> erlang:error({badoption, BadOpt}) end, + BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)), + wxe_util:call(?wxSystemSettings_GetMetric, + <<Index:32/?UI, 0:32,BinOpt/binary>>). + +%% @spec () -> WxSystemScreenType +%% WxSystemScreenType = integer() +%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html#wxsystemsettingsgetscreentype">external documentation</a>. +%%<br /> WxSystemScreenType is one of ?wxSYS_SCREEN_NONE | ?wxSYS_SCREEN_TINY | ?wxSYS_SCREEN_PDA | ?wxSYS_SCREEN_SMALL | ?wxSYS_SCREEN_DESKTOP +getScreenType() -> + wxe_util:call(?wxSystemSettings_GetScreenType, + <<>>). + diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index 6f43247d74..7b8d510d40 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -58,7 +58,8 @@ all(suite) -> helpFrame, htmlWindow, listCtrlSort, - radioBox + radioBox, + systemSettings ]. %% The test cases @@ -392,3 +393,17 @@ radioBox(Config) -> wxWindow:show(Frame), wx_test_lib:wx_destroy(Frame,Config). + + +systemSettings(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +systemSettings(Config) -> + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"), + + ?m({_,_,_,_}, wxSystemSettings:getColour(?wxSYS_COLOUR_DESKTOP)), + ?mt(wxFont, wxSystemSettings:getFont(?wxSYS_SYSTEM_FONT)), + ?m(true, is_integer(wxSystemSettings:getMetric(?wxSYS_MOUSE_BUTTONS))), + ?m(true, is_integer(wxSystemSettings:getScreenType())), + + wxWindow:show(Frame), + wx_test_lib:wx_destroy(Frame,Config). 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 |